2 * Copyright (c) 2003 SkyRope, LLC
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * - Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * - Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * - Neither the name of Skyrope, LLC nor the names of its contributors may be
14 * used to endorse or promote products derived from this software without
15 * specific prior written permission from Skyrope, LLC.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * Portions of this code are derived from portions of the MIT
30 * Leash Ticket Manager and LoadFuncs utilities. For these portions the
31 * following copyright applies.
33 * Copyright (c) 2003,2004 by the Massachusetts Institute of Technology.
34 * All rights reserved.
36 * Export of this software from the United States of America may
37 * require a specific license from the United States Government.
38 * It is the responsibility of any person or organization contemplating
39 * export to obtain such a license before exporting.
41 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
42 * distribute this software and its documentation for any purpose and
43 * without fee is hereby granted, provided that the above copyright
44 * notice appear in all copies and that both that copyright notice and
45 * this permission notice appear in supporting documentation, and that
46 * the name of M.I.T. not be used in advertising or publicity pertaining
47 * to distribution of the software without specific, written prior
48 * permission. Furthermore if you modify this software you must label
49 * your software as modified software and not distribute it in such a
50 * fashion that it might be confused with the original M.I.T. software.
51 * M.I.T. makes no representations about the suitability of
52 * this software for any purpose. It is provided "as is" without express
53 * or implied warranty.
57 // IP Change Monitoring Functions
71 #include "ipaddrchg.h"
76 #define MAXCELLCHARS 64
79 // Cell Accessibility Functions
80 // based on work originally submitted to the CMU Computer Club
81 // by Jeffrey Hutzelman
83 // These would work great if the fsProbe interface had been
94 unsigned short port
; // in
95 int retry_delay
; // in seconds
98 int wait
; // in seconds
99 int retry
; // in attempts
102 int hosts_attempted
; // out
105 // the fsHandler is where we receive the answer to the probe
109 ping_count
= fsprobe_Results
.probeNum
;
110 if (!*fsprobe_Results
.probeOK
)
113 if (waiting
) complete();
115 if (ping_count
== retry
)
120 // ping_fs is a callback routine meant to be called from within
121 // cm_SearchCellFile() or cm_SearchCellDNS()
123 pingFS(void *ping_params
, struct sockaddr_in
*addrp
, char *namep
)
126 struct ping_params
* pp
= (struct ping_params
*) ping_params
;
128 if ( pp
->max_hosts
&& pp
->hosts_attempted
>= pp
->max_hosts
)
131 pp
->hosts_attempted
++;
133 if (pp
->port
&& addrp
->sin_port
!= htons(pp
->port
))
134 addrp
->sin_port
= htons(pp
->port
);
136 rc
= fsprobe_Init(1, addrp
, pp
->retry_delay
, fsHandler
, pp
->verbose
);
139 fprintf(stderr
, "fsprobe_Init failed (%d)\n", rc
);
146 tv
.tv_sec
= pp
->host
.wait
;
148 if (IOMGR_Select(0, 0, 0, 0, &tv
))
160 char rootcell
[MAXCELLCHARS
+1];
161 char newcell
[MAXCELLCHARS
+1];
162 struct ping_params pp
;
164 memset(&pp
, 0, sizeof(struct ping_params
));
166 if (!cell
|| strlen(cell
) == 0) {
167 /* WIN32 NOTE: no way to get max chars */
168 if (rc
= pcm_GetRootCellName(rootcell
))
173 pp
.port
= 7000; // AFS FileServer
180 /* WIN32: cm_SearchCellFile(cell, newcell, linkedCell, pcallback, pdata) */
181 rc
= pcm_SearchCellFile(cell
, newcell
, pingFS
, (void *)&pp
);
183 #endif /* USE_FSPROBE */
185 // These two items are imported from afscreds.h
186 // but it cannot be included without causing conflicts
187 #define c100ns1SECOND (LONGLONG)10000000
189 TimeToSystemTime (SYSTEMTIME
*pst
, time_t TimeT
)
192 memset (pst
, 0x00, sizeof(SYSTEMTIME
));
194 if ((pTime
= localtime (&TimeT
)) != NULL
)
196 pst
->wYear
= pTime
->tm_year
+ 1900;
197 pst
->wMonth
= pTime
->tm_mon
+ 1;
198 pst
->wDayOfWeek
= pTime
->tm_wday
;
199 pst
->wDay
= pTime
->tm_mday
;
200 pst
->wHour
= pTime
->tm_hour
;
201 pst
->wMinute
= pTime
->tm_min
;
202 pst
->wSecond
= pTime
->tm_sec
;
203 pst
->wMilliseconds
= 0;
209 LPSTR lpszMachineName
,
210 LPSTR lpszServiceName
,
211 DWORD
*lpdwCurrentState
)
214 SC_HANDLE schSCManager
= NULL
;
215 SC_HANDLE schService
= NULL
;
216 DWORD fdwDesiredAccess
= 0;
217 SERVICE_STATUS ssServiceStatus
= {0};
220 *lpdwCurrentState
= 0;
222 fdwDesiredAccess
= GENERIC_READ
;
224 schSCManager
= OpenSCManager(lpszMachineName
,
228 if(schSCManager
== NULL
)
234 schService
= OpenService(schSCManager
,
238 if(schService
== NULL
)
244 fRet
= QueryServiceStatus(schService
,
253 *lpdwCurrentState
= ssServiceStatus
.dwCurrentState
;
257 CloseServiceHandle(schService
);
258 CloseServiceHandle(schSCManager
);
264 ObtainTokensFromUserIfNeeded(HWND hWnd
)
266 char * rootcell
= NULL
;
267 char cell
[MAXCELLCHARS
+1] = "";
268 char password
[PROBE_PASSWORD_LEN
+1];
269 struct afsconf_cell cellconfig
;
270 struct ktc_principal aserver
;
271 struct ktc_principal aclient
;
272 struct ktc_token atoken
;
273 krb5_timestamp now
= 0;
274 BOOL serverReachable
= 0;
276 DWORD CurrentState
, code
;
278 int use_kfw
= KFW_is_available();
285 SYSTEMTIME stExpires
;
288 memset(HostName
, '\0', sizeof(HostName
));
289 gethostname(HostName
, sizeof(HostName
));
290 if (GetServiceStatus(HostName
, TRANSARCAFSDAEMON
, &CurrentState
) != NOERROR
)
292 if (CurrentState
!= SERVICE_RUNNING
) {
293 SendMessage(hWnd
, WM_START_SERVICE
, FALSE
, 0L);
297 rootcell
= (char *)GlobalAlloc(GPTR
,MAXCELLCHARS
+1);
301 code
= KFW_AFS_get_cellconfig(cell
, (void*)&cellconfig
, rootcell
);
305 memset(&aserver
, '\0', sizeof(aserver
));
306 strcpy(aserver
.name
, "afs");
307 strcpy(aserver
.cell
, rootcell
);
309 GetLocalTime (&stNow
);
310 SystemTimeToFileTime (&stNow
, &ftNow
);
311 llNow
= (((LONGLONG
)ftNow
.dwHighDateTime
) << 32) + (LONGLONG
)(ftNow
.dwLowDateTime
);
312 llNow
/= c100ns1SECOND
;
314 rc
= ktc_GetToken(&aserver
, &atoken
, sizeof(atoken
), &aclient
);
316 TimeToSystemTime (&stExpires
, atoken
.endTime
);
317 SystemTimeToFileTime (&stExpires
, &ftExpires
);
318 llExpires
= (((LONGLONG
)ftExpires
.dwHighDateTime
) << 32) + (LONGLONG
)(ftExpires
.dwLowDateTime
);
319 llExpires
/= c100ns1SECOND
;
321 if (llNow
< llExpires
)
324 if ( IsDebuggerPresent() ) {
326 sprintf(message
,"ObtainTokensFromUserIfNeeded: %d now = %ul endTime = %ul\n",
327 rc
, llNow
, llExpires
);
328 OutputDebugString(message
);
333 serverReachable
= cellPing(NULL
);
336 // If we can't use the FSProbe interface we can attempt to forge
337 // a kinit and if we can back an invalid user error we know the
338 // kdc is at least reachable
339 serverReachable
= KFW_probe_kdc(&cellconfig
);
343 for ( i
=0 ; i
<PROBE_PASSWORD_LEN
; i
++ )
346 code
= ObtainNewCredentials(rootcell
, PROBE_USERNAME
, password
, TRUE
);
349 case KERB_ERR_PRINCIPAL_UNKNOWN
:
350 case KERB_ERR_SERVICE_EXP
:
352 serverReachable
= TRUE
;
355 serverReachable
= FALSE
;
359 if ( !serverReachable
) {
360 if ( IsDebuggerPresent() )
361 OutputDebugString("Server Unreachable\n");
365 if ( IsDebuggerPresent() )
366 OutputDebugString("Server Reachable\n");
370 KFW_import_windows_lsa();
371 #endif /* USE_MS2MIT */
372 KFW_AFS_renew_expiring_tokens();
373 KFW_AFS_renew_token_for_cell(rootcell
);
375 rc
= ktc_GetToken(&aserver
, &atoken
, sizeof(atoken
), &aclient
);
377 TimeToSystemTime (&stExpires
, atoken
.endTime
);
378 SystemTimeToFileTime (&stExpires
, &ftExpires
);
379 llExpires
= (((LONGLONG
)ftExpires
.dwHighDateTime
) << 32) + (LONGLONG
)(ftExpires
.dwLowDateTime
);
380 llExpires
/= c100ns1SECOND
;
382 if (llNow
< llExpires
)
387 SendMessage(hWnd
, WM_OBTAIN_TOKENS
, FALSE
, (long)rootcell
);
388 rootcell
= NULL
; // rootcell freed by message receiver
392 GlobalFree(rootcell
);
398 GetNumOfIpAddrs(void)
400 PMIB_IPADDRTABLE pIpAddrTable
= NULL
;
404 DWORD validAddrs
= 0;
407 code
= GetIpAddrTable(NULL
, &dwSize
, 0);
408 if (code
== ERROR_INSUFFICIENT_BUFFER
) {
409 pIpAddrTable
= malloc(dwSize
);
410 code
= GetIpAddrTable(pIpAddrTable
, &dwSize
, 0);
411 if ( code
== NO_ERROR
) {
412 for ( index
=0; index
< pIpAddrTable
->dwNumEntries
; index
++ ) {
413 if (pIpAddrTable
->table
[index
].dwAddr
!= 0)
423 IpAddrChangeMonitor(void * hWnd
)
425 #ifdef USE_OVERLAPPED
426 HANDLE Handle
= INVALID_HANDLE_VALUE
; /* Do Not Close This Handle */
428 #endif /* USE_OVERLAPPED */
430 DWORD prevNumOfAddrs
= GetNumOfIpAddrs();
438 #ifdef USE_OVERLAPPED
439 ZeroMemory(&Ovlap
, sizeof(OVERLAPPED
));
441 Result
= NotifyAddrChange(&Handle
,&Ovlap
);
442 if (Result
!= ERROR_IO_PENDING
)
444 if ( IsDebuggerPresent() ) {
445 sprintf(message
, "NotifyAddrChange() failed with error %d \n", Result
);
446 OutputDebugString(message
);
451 if ((Result
= WaitForSingleObject(Handle
,INFINITE
)) != WAIT_OBJECT_0
)
453 if ( IsDebuggerPresent() ) {
454 sprintf(message
, "WaitForSingleObject() failed with error %d\n",
456 OutputDebugString(message
);
461 if (GetOverlappedResult(Handle
, &Ovlap
,
462 &DataTransfered
, TRUE
) == 0)
464 if ( IsDebuggerPresent() ) {
465 sprintf(message
, "GetOverlapped result failed %d \n",
467 OutputDebugString(message
);
472 Result
= NotifyAddrChange(NULL
,NULL
);
473 if (Result
!= NO_ERROR
)
475 if ( IsDebuggerPresent() ) {
476 sprintf(message
, "NotifyAddrChange() failed with error %d \n", Result
);
477 OutputDebugString(message
);
483 NumOfAddrs
= GetNumOfIpAddrs();
485 if ( IsDebuggerPresent() ) {
486 sprintf(message
,"IPAddrChangeMonitor() NumOfAddrs: now %d was %d\n",
487 NumOfAddrs
, prevNumOfAddrs
);
488 OutputDebugString(message
);
491 if ( NumOfAddrs
!= prevNumOfAddrs
) {
492 // Give AFS Client Service a chance to notice and die
493 // Or for network services to startup
495 // this call should probably be mutex protected
496 ObtainTokensFromUserIfNeeded(hWnd
);
498 prevNumOfAddrs
= NumOfAddrs
;
504 IpAddrChangeMonitorInit(HWND hWnd
)
506 DWORD status
= ERROR_SUCCESS
;
510 thread
= CreateThread(NULL
, 0, (PTHREAD_START_ROUTINE
)IpAddrChangeMonitor
,
513 if (thread
== NULL
) {
514 status
= GetLastError();