Update NEWS for 1.6.22
[pkg-k5-afs_openafs.git] / src / WINNT / client_creds / ipaddrchg.c
blob0201c4471653ec4728558839c39fd86adc9063c3
1 /*
2 * Copyright (c) 2003 SkyRope, LLC
3 * All rights reserved.
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
59 #include <windows.h>
60 #include <stdio.h>
61 #include <string.h>
62 #include <time.h>
63 #include <winsock2.h>
65 #define USE_MS2MIT 1
67 #include <afs/stds.h>
68 #include <krb5.h>
69 #include <rx\rxkad.h>
70 #include <afskfw.h>
71 #include "ipaddrchg.h"
72 #include "creds.h"
73 #include <iphlpapi.h>
74 #include <afs/auth.h>
76 #define MAXCELLCHARS 64
78 #ifdef USE_FSPROBE
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
84 // ported to Windows
86 static
87 void probeComplete()
89 fsprobe_Cleanup(1);
90 rx_Finalize();
93 struct ping_params {
94 unsigned short port; // in
95 int retry_delay; // in seconds
96 int verbose; // in
97 struct {
98 int wait; // in seconds
99 int retry; // in attempts
100 } host;
101 int max_hosts; // in
102 int hosts_attempted; // out
105 // the fsHandler is where we receive the answer to the probe
106 static
107 int fsHandler(void)
109 ping_count = fsprobe_Results.probeNum;
110 if (!*fsprobe_Results.probeOK)
112 ok_count++;
113 if (waiting) complete();
115 if (ping_count == retry)
116 complete();
117 return 0;
120 // ping_fs is a callback routine meant to be called from within
121 // cm_SearchCellFile() or cm_SearchCellDNS()
122 static long
123 pingFS(void *ping_params, struct sockaddr_in *addrp, char *namep)
125 int rc;
126 struct ping_params * pp = (struct ping_params *) ping_params;
128 if ( pp->max_hosts && pp->hosts_attempted >= pp->max_hosts )
129 return 0;
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);
137 if (rc)
139 fprintf(stderr, "fsprobe_Init failed (%d)\n", rc);
140 fsprobe_Cleanup(1);
141 return 0;
144 for (;;)
146 tv.tv_sec = pp->host.wait;
147 tv.tv_usec = 0;
148 if (IOMGR_Select(0, 0, 0, 0, &tv))
149 break;
151 probeComplete();
152 return(0);
156 static BOOL
157 pingCell(char *cell)
159 int rc;
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))
169 return(FALSE);
170 cell = rootcell;
173 pp.port = 7000; // AFS FileServer
174 pp.retry_delay = 10;
175 pp.max_hosts = 3;
176 pp.host.wait = 30;
177 pp.host.retry = 0;
178 pp.verbose = 1;
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
188 static void
189 TimeToSystemTime (SYSTEMTIME *pst, time_t TimeT)
191 struct tm *pTime;
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;
207 static DWORD
208 GetServiceStatus(
209 LPSTR lpszMachineName,
210 LPSTR lpszServiceName,
211 DWORD *lpdwCurrentState)
213 DWORD hr = NOERROR;
214 SC_HANDLE schSCManager = NULL;
215 SC_HANDLE schService = NULL;
216 DWORD fdwDesiredAccess = 0;
217 SERVICE_STATUS ssServiceStatus = {0};
218 BOOL fRet = FALSE;
220 *lpdwCurrentState = 0;
222 fdwDesiredAccess = GENERIC_READ;
224 schSCManager = OpenSCManager(lpszMachineName,
225 NULL,
226 fdwDesiredAccess);
228 if(schSCManager == NULL)
230 hr = GetLastError();
231 goto cleanup;
234 schService = OpenService(schSCManager,
235 lpszServiceName,
236 fdwDesiredAccess);
238 if(schService == NULL)
240 hr = GetLastError();
241 goto cleanup;
244 fRet = QueryServiceStatus(schService,
245 &ssServiceStatus);
247 if(fRet == FALSE)
249 hr = GetLastError();
250 goto cleanup;
253 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
255 cleanup:
257 CloseServiceHandle(schService);
258 CloseServiceHandle(schSCManager);
260 return(hr);
263 void
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;
275 int rc;
276 DWORD CurrentState, code;
277 char HostName[64];
278 int use_kfw = KFW_is_available();
280 SYSTEMTIME stNow;
281 FILETIME ftNow;
282 LONGLONG llNow;
283 FILETIME ftExpires;
284 LONGLONG llExpires;
285 SYSTEMTIME stExpires;
287 CurrentState = 0;
288 memset(HostName, '\0', sizeof(HostName));
289 gethostname(HostName, sizeof(HostName));
290 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
291 return;
292 if (CurrentState != SERVICE_RUNNING) {
293 SendMessage(hWnd, WM_START_SERVICE, FALSE, 0L);
294 return;
297 rootcell = (char *)GlobalAlloc(GPTR,MAXCELLCHARS+1);
298 if (!rootcell)
299 goto cleanup;
301 code = KFW_AFS_get_cellconfig(cell, (void*)&cellconfig, rootcell);
302 if (code)
303 goto cleanup;
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);
315 if ( rc == 0 ) {
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)
322 goto cleanup;
324 if ( IsDebuggerPresent() ) {
325 char message[256];
326 sprintf(message,"ObtainTokensFromUserIfNeeded: %d now = %ul endTime = %ul\n",
327 rc, llNow, llExpires);
328 OutputDebugString(message);
332 #ifdef USE_FSPROBE
333 serverReachable = cellPing(NULL);
334 #else
335 if (use_kfw) {
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);
340 } else {
341 int i;
343 for ( i=0 ; i<PROBE_PASSWORD_LEN ; i++ )
344 password[i] = 'x';
346 code = ObtainNewCredentials(rootcell, PROBE_USERNAME, password, TRUE);
347 switch ( code ) {
348 case INTK_BADPW:
349 case KERB_ERR_PRINCIPAL_UNKNOWN:
350 case KERB_ERR_SERVICE_EXP:
351 case RD_AP_TIME:
352 serverReachable = TRUE;
353 break;
354 default:
355 serverReachable = FALSE;
358 #endif
359 if ( !serverReachable ) {
360 if ( IsDebuggerPresent() )
361 OutputDebugString("Server Unreachable\n");
362 goto cleanup;
365 if ( IsDebuggerPresent() )
366 OutputDebugString("Server Reachable\n");
368 if ( use_kfw ) {
369 #ifdef USE_MS2MIT
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);
376 if ( rc == 0 ) {
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)
383 goto cleanup;
387 SendMessage(hWnd, WM_OBTAIN_TOKENS, FALSE, (long)rootcell);
388 rootcell = NULL; // rootcell freed by message receiver
390 cleanup:
391 if (rootcell)
392 GlobalFree(rootcell);
394 return;
397 DWORD
398 GetNumOfIpAddrs(void)
400 PMIB_IPADDRTABLE pIpAddrTable = NULL;
401 ULONG dwSize;
402 DWORD code;
403 DWORD index;
404 DWORD validAddrs = 0;
406 dwSize = 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)
414 validAddrs++;
417 free(pIpAddrTable);
419 return validAddrs;
422 void
423 IpAddrChangeMonitor(void * hWnd)
425 #ifdef USE_OVERLAPPED
426 HANDLE Handle = INVALID_HANDLE_VALUE; /* Do Not Close This Handle */
427 OVERLAPPED Ovlap;
428 #endif /* USE_OVERLAPPED */
429 DWORD Result;
430 DWORD prevNumOfAddrs = GetNumOfIpAddrs();
431 DWORD NumOfAddrs;
432 char message[256];
434 if ( !hWnd )
435 return;
437 while ( TRUE ) {
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);
448 break;
451 if ((Result = WaitForSingleObject(Handle,INFINITE)) != WAIT_OBJECT_0)
453 if ( IsDebuggerPresent() ) {
454 sprintf(message, "WaitForSingleObject() failed with error %d\n",
455 GetLastError());
456 OutputDebugString(message);
458 continue;
461 if (GetOverlappedResult(Handle, &Ovlap,
462 &DataTransfered, TRUE) == 0)
464 if ( IsDebuggerPresent() ) {
465 sprintf(message, "GetOverlapped result failed %d \n",
466 GetLastError());
467 OutputDebugString(message);
469 break;
471 #else
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);
479 break;
481 #endif
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
494 Sleep(2000);
495 // this call should probably be mutex protected
496 ObtainTokensFromUserIfNeeded(hWnd);
498 prevNumOfAddrs = NumOfAddrs;
503 DWORD
504 IpAddrChangeMonitorInit(HWND hWnd)
506 DWORD status = ERROR_SUCCESS;
507 HANDLE thread;
508 ULONG threadID = 0;
510 thread = CreateThread(NULL, 0, (PTHREAD_START_ROUTINE)IpAddrChangeMonitor,
511 hWnd, 0, &threadID);
513 if (thread == NULL) {
514 status = GetLastError();
516 CloseHandle(thread);
517 return status;