/* * Copyright (c) 2003 SkyRope, LLC * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of Skyrope, LLC nor the names of its contributors may be * used to endorse or promote products derived from this software without * specific prior written permission from Skyrope, LLC. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Portions of this code are derived from portions of the MIT * Leash Ticket Manager and LoadFuncs utilities. For these portions the * following copyright applies. * * Copyright (c) 2003,2004 by the Massachusetts Institute of Technology. * All rights reserved. * * Export of this software from the United States of America may * require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. * */ // IP Change Monitoring Functions #include #include #include #include #include #define USE_MS2MIT 1 #include #include #include #include #include "ipaddrchg.h" #include "creds.h" #include #include #define MAXCELLCHARS 64 #ifdef USE_FSPROBE // Cell Accessibility Functions // based on work originally submitted to the CMU Computer Club // by Jeffrey Hutzelman // // These would work great if the fsProbe interface had been // ported to Windows static void probeComplete() { fsprobe_Cleanup(1); rx_Finalize(); } struct ping_params { unsigned short port; // in int retry_delay; // in seconds int verbose; // in struct { int wait; // in seconds int retry; // in attempts } host; int max_hosts; // in int hosts_attempted; // out } // the fsHandler is where we receive the answer to the probe static int fsHandler(void) { ping_count = fsprobe_Results.probeNum; if (!*fsprobe_Results.probeOK) { ok_count++; if (waiting) complete(); } if (ping_count == retry) complete(); return 0; } // ping_fs is a callback routine meant to be called from within // cm_SearchCellFile() or cm_SearchCellDNS() static long pingFS(void *ping_params, struct sockaddr_in *addrp, char *namep) { int rc; struct ping_params * pp = (struct ping_params *) ping_params; if ( pp->max_hosts && pp->hosts_attempted >= pp->max_hosts ) return 0; pp->hosts_attempted++; if (pp->port && addrp->sin_port != htons(pp->port)) addrp->sin_port = htons(pp->port); rc = fsprobe_Init(1, addrp, pp->retry_delay, fsHandler, pp->verbose); if (rc) { fprintf(stderr, "fsprobe_Init failed (%d)\n", rc); fsprobe_Cleanup(1); return 0; } for (;;) { tv.tv_sec = pp->host.wait; tv.tv_usec = 0; if (IOMGR_Select(0, 0, 0, 0, &tv)) break; } probeComplete(); return(0); } static BOOL pingCell(char *cell) { int rc; char rootcell[MAXCELLCHARS+1]; char newcell[MAXCELLCHARS+1]; struct ping_params pp; memset(&pp, 0, sizeof(struct ping_params)); if (!cell || strlen(cell) == 0) { /* WIN32 NOTE: no way to get max chars */ if (rc = pcm_GetRootCellName(rootcell)) return(FALSE); cell = rootcell; } pp.port = 7000; // AFS FileServer pp.retry_delay = 10; pp.max_hosts = 3; pp.host.wait = 30; pp.host.retry = 0; pp.verbose = 1; /* WIN32: cm_SearchCellFile(cell, newcell, linkedCell, pcallback, pdata) */ rc = pcm_SearchCellFile(cell, newcell, pingFS, (void *)&pp); } #endif /* USE_FSPROBE */ // These two items are imported from afscreds.h // but it cannot be included without causing conflicts #define c100ns1SECOND (LONGLONG)10000000 static void TimeToSystemTime (SYSTEMTIME *pst, time_t TimeT) { struct tm *pTime; memset (pst, 0x00, sizeof(SYSTEMTIME)); if ((pTime = localtime (&TimeT)) != NULL) { pst->wYear = pTime->tm_year + 1900; pst->wMonth = pTime->tm_mon + 1; pst->wDayOfWeek = pTime->tm_wday; pst->wDay = pTime->tm_mday; pst->wHour = pTime->tm_hour; pst->wMinute = pTime->tm_min; pst->wSecond = pTime->tm_sec; pst->wMilliseconds = 0; } } static DWORD GetServiceStatus( LPSTR lpszMachineName, LPSTR lpszServiceName, DWORD *lpdwCurrentState) { DWORD hr = NOERROR; SC_HANDLE schSCManager = NULL; SC_HANDLE schService = NULL; DWORD fdwDesiredAccess = 0; SERVICE_STATUS ssServiceStatus = {0}; BOOL fRet = FALSE; *lpdwCurrentState = 0; fdwDesiredAccess = GENERIC_READ; schSCManager = OpenSCManager(lpszMachineName, NULL, fdwDesiredAccess); if(schSCManager == NULL) { hr = GetLastError(); goto cleanup; } schService = OpenService(schSCManager, lpszServiceName, fdwDesiredAccess); if(schService == NULL) { hr = GetLastError(); goto cleanup; } fRet = QueryServiceStatus(schService, &ssServiceStatus); if(fRet == FALSE) { hr = GetLastError(); goto cleanup; } *lpdwCurrentState = ssServiceStatus.dwCurrentState; cleanup: CloseServiceHandle(schService); CloseServiceHandle(schSCManager); return(hr); } void ObtainTokensFromUserIfNeeded(HWND hWnd) { char * rootcell = NULL; char cell[MAXCELLCHARS+1] = ""; char password[PROBE_PASSWORD_LEN+1]; struct afsconf_cell cellconfig; struct ktc_principal aserver; struct ktc_principal aclient; struct ktc_token atoken; krb5_timestamp now = 0; BOOL serverReachable = 0; int rc; DWORD CurrentState, code; char HostName[64]; int use_kfw = KFW_is_available(); SYSTEMTIME stNow; FILETIME ftNow; LONGLONG llNow; FILETIME ftExpires; LONGLONG llExpires; SYSTEMTIME stExpires; CurrentState = 0; memset(HostName, '\0', sizeof(HostName)); gethostname(HostName, sizeof(HostName)); if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR) return; if (CurrentState != SERVICE_RUNNING) { SendMessage(hWnd, WM_START_SERVICE, FALSE, 0L); return; } rootcell = (char *)GlobalAlloc(GPTR,MAXCELLCHARS+1); if (!rootcell) goto cleanup; code = KFW_AFS_get_cellconfig(cell, (void*)&cellconfig, rootcell); if (code) goto cleanup; memset(&aserver, '\0', sizeof(aserver)); strcpy(aserver.name, "afs"); strcpy(aserver.cell, rootcell); GetLocalTime (&stNow); SystemTimeToFileTime (&stNow, &ftNow); llNow = (((LONGLONG)ftNow.dwHighDateTime) << 32) + (LONGLONG)(ftNow.dwLowDateTime); llNow /= c100ns1SECOND; rc = ktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient); if ( rc == 0 ) { TimeToSystemTime (&stExpires, atoken.endTime); SystemTimeToFileTime (&stExpires, &ftExpires); llExpires = (((LONGLONG)ftExpires.dwHighDateTime) << 32) + (LONGLONG)(ftExpires.dwLowDateTime); llExpires /= c100ns1SECOND; if (llNow < llExpires) goto cleanup; if ( IsDebuggerPresent() ) { char message[256]; sprintf(message,"ObtainTokensFromUserIfNeeded: %d now = %ul endTime = %ul\n", rc, llNow, llExpires); OutputDebugString(message); } } #ifdef USE_FSPROBE serverReachable = cellPing(NULL); #else if (use_kfw) { // If we can't use the FSProbe interface we can attempt to forge // a kinit and if we can back an invalid user error we know the // kdc is at least reachable serverReachable = KFW_probe_kdc(&cellconfig); } else { int i; for ( i=0 ; idwNumEntries; index++ ) { if (pIpAddrTable->table[index].dwAddr != 0) validAddrs++; } } free(pIpAddrTable); } return validAddrs; } void IpAddrChangeMonitor(void * hWnd) { #ifdef USE_OVERLAPPED HANDLE Handle = INVALID_HANDLE_VALUE; /* Do Not Close This Handle */ OVERLAPPED Ovlap; #endif /* USE_OVERLAPPED */ DWORD Result; DWORD prevNumOfAddrs = GetNumOfIpAddrs(); DWORD NumOfAddrs; char message[256]; if ( !hWnd ) return; while ( TRUE ) { #ifdef USE_OVERLAPPED ZeroMemory(&Ovlap, sizeof(OVERLAPPED)); Result = NotifyAddrChange(&Handle,&Ovlap); if (Result != ERROR_IO_PENDING) { if ( IsDebuggerPresent() ) { sprintf(message, "NotifyAddrChange() failed with error %d \n", Result); OutputDebugString(message); } break; } if ((Result = WaitForSingleObject(Handle,INFINITE)) != WAIT_OBJECT_0) { if ( IsDebuggerPresent() ) { sprintf(message, "WaitForSingleObject() failed with error %d\n", GetLastError()); OutputDebugString(message); } continue; } if (GetOverlappedResult(Handle, &Ovlap, &DataTransfered, TRUE) == 0) { if ( IsDebuggerPresent() ) { sprintf(message, "GetOverlapped result failed %d \n", GetLastError()); OutputDebugString(message); } break; } #else Result = NotifyAddrChange(NULL,NULL); if (Result != NO_ERROR) { if ( IsDebuggerPresent() ) { sprintf(message, "NotifyAddrChange() failed with error %d \n", Result); OutputDebugString(message); } break; } #endif NumOfAddrs = GetNumOfIpAddrs(); if ( IsDebuggerPresent() ) { sprintf(message,"IPAddrChangeMonitor() NumOfAddrs: now %d was %d\n", NumOfAddrs, prevNumOfAddrs); OutputDebugString(message); } if ( NumOfAddrs != prevNumOfAddrs ) { // Give AFS Client Service a chance to notice and die // Or for network services to startup Sleep(2000); // this call should probably be mutex protected ObtainTokensFromUserIfNeeded(hWnd); } prevNumOfAddrs = NumOfAddrs; } } DWORD IpAddrChangeMonitorInit(HWND hWnd) { DWORD status = ERROR_SUCCESS; HANDLE thread; ULONG threadID = 0; thread = CreateThread(NULL, 0, (PTHREAD_START_ROUTINE)IpAddrChangeMonitor, hWnd, 0, &threadID); if (thread == NULL) { status = GetLastError(); } CloseHandle(thread); return status; }