getipaddrlist-20040318
[openafs.git] / src / WINNT / client_creds / afskfw.c
index 3ced3f8..bedb85f 100644 (file)
@@ -397,34 +397,50 @@ void
 KFW_initialize(void)
 {
     static int inited = 0;
+
     if ( !inited ) {
-        inited = 1;
-        LoadFuncs(KRB5_DLL, k5_fi, &hKrb5, 0, 1, 0, 0);
-        LoadFuncs(KRB4_DLL, k4_fi, &hKrb5, 0, 1, 0, 0);
-        LoadFuncs(COMERR_DLL, ce_fi, &hComErr, 0, 0, 1, 0);
-        LoadFuncs(SERVICE_DLL, service_fi, &hService, 0, 1, 0, 0);
+        char mutexName[MAX_PATH];
+        HANDLE hMutex = NULL;
+
+        sprintf(mutexName, "AFS KFW Init pid=%d", getpid());
+        
+        hMutex = CreateMutex( NULL, TRUE, mutexName );
+        if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
+            if ( WaitForSingleObject( hMutex, INFINITE ) != WAIT_OBJECT_0 ) {
+                return;
+            }
+        }
+        if ( !inited ) {
+            inited = 1;
+            LoadFuncs(KRB5_DLL, k5_fi, &hKrb5, 0, 1, 0, 0);
+            LoadFuncs(KRB4_DLL, k4_fi, &hKrb4, 0, 1, 0, 0);
+            LoadFuncs(COMERR_DLL, ce_fi, &hComErr, 0, 0, 1, 0);
+            LoadFuncs(SERVICE_DLL, service_fi, &hService, 0, 1, 0, 0);
 #ifdef USE_MS2MIT
-        LoadFuncs(SECUR32_DLL, lsa_fi, &hSecur32, 0, 1, 1, 1);
+            LoadFuncs(SECUR32_DLL, lsa_fi, &hSecur32, 0, 1, 1, 1);
 #endif /* USE_MS2MIT */
-        LoadFuncs(KRB524_DLL, k524_fi, &hKrb524, 0, 1, 1, 1);
-        LoadFuncs(PROFILE_DLL, profile_fi, &hProfile, 0, 1, 0, 0);
-        LoadFuncs(AFSTOKENS_DLL, afst_fi, &hAfsTokens, 0, 1, 0, 0);
-        LoadFuncs(AFSCONF_DLL, afsc_fi, &hAfsConf, 0, 1, 0, 0);
-        LoadFuncs(LEASH_DLL, leash_fi, &hLeash, 0, 1, 0, 0);
-        LoadFuncs(CCAPI_DLL, ccapi_fi, &hCCAPI, 0, 1, 0, 0);
-
-        if ( KFW_is_available() ) {
-            char rootcell[MAXCELLCHARS+1];
+            LoadFuncs(KRB524_DLL, k524_fi, &hKrb524, 0, 1, 1, 1);
+            LoadFuncs(PROFILE_DLL, profile_fi, &hProfile, 0, 1, 0, 0);
+            LoadFuncs(AFSTOKENS_DLL, afst_fi, &hAfsTokens, 0, 1, 0, 0);
+            LoadFuncs(AFSCONF_DLL, afsc_fi, &hAfsConf, 0, 1, 0, 0);
+            LoadFuncs(LEASH_DLL, leash_fi, &hLeash, 0, 1, 0, 0);
+            LoadFuncs(CCAPI_DLL, ccapi_fi, &hCCAPI, 0, 1, 0, 0);
+
+            if ( KFW_is_available() ) {
+                char rootcell[MAXCELLCHARS+1];
 #ifdef USE_MS2MIT
-            KFW_import_windows_lsa();
+                KFW_import_windows_lsa();
 #endif /* USE_MS2MIT */
-            KFW_import_ccache_data();
-                   KFW_AFS_renew_expiring_credentials();
+                KFW_import_ccache_data();
+                KFW_AFS_renew_expiring_tokens();
 
-            /* WIN32 NOTE: no way to get max chars */
-            if (!pcm_GetRootCellName(rootcell))
-                KFW_AFS_renew_token_for_cell(rootcell);
+                /* WIN32 NOTE: no way to get max chars */
+                if (!pcm_GetRootCellName(rootcell))
+                    KFW_AFS_renew_token_for_cell(rootcell);
+            }
         }
+        ReleaseMutex(hMutex);
+        CloseHandle(hMutex);
     }
 }
 
@@ -457,7 +473,7 @@ KFW_cleanup(void)
         FreeLibrary(hCCAPI);
 }
 
-char OpenAFSConfigKeyName[] = "SOFTWARE\\OpenAFS\\Client";
+static char OpenAFSConfigKeyName[] = "SOFTWARE\\OpenAFS\\Client";
 
 int 
 KFW_is_available(void)
@@ -466,10 +482,10 @@ KFW_is_available(void)
        DWORD code, len;
     DWORD enableKFW = 1;
 
-    code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, OpenAFSConfigKeyName,
+    code = RegOpenKeyEx(HKEY_CURRENT_USER, OpenAFSConfigKeyName,
                          0, KEY_QUERY_VALUE, &parmKey);
     if (code != ERROR_SUCCESS)
-        code = RegOpenKeyEx(HKEY_CURRENT_USER, OpenAFSConfigKeyName,
+        code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, OpenAFSConfigKeyName,
                              0, KEY_QUERY_VALUE, &parmKey);
        if (code == ERROR_SUCCESS) {
         len = sizeof(enableKFW);
@@ -490,7 +506,7 @@ KFW_is_available(void)
          hSecur32 && 
 #endif /* USE_MS2MIT */
          hKrb524 &&
-         hProfile && hAfsTokens && hAfsConf )
+         hProfile && hAfsTokens && hAfsConf && hLeash && hCCAPI )
         return TRUE;
     return FALSE;
 }
@@ -832,6 +848,9 @@ KFW_get_ccache(krb5_context alt_ctx, krb5_principal principal, krb5_ccache * cc)
     char * ccname = 0;
     krb5_error_code code;
 
+    if (!pkrb5_init_context)
+        return 0;
+
     if ( alt_ctx ) {
         ctx = alt_ctx;
     } else {
@@ -878,6 +897,9 @@ KFW_import_windows_lsa(void)
     char cell[128]="";
     int i;
          
+    if (!pkrb5_init_context)
+        return;
+
     if ( !MSLSA_IsKerberosLogon() )
         return;
 
@@ -1138,6 +1160,9 @@ KFW_AFS_get_cred(char * username,
     int  cell_count=0;
     afsconf_cell cellconfig;
 
+    if (!pkrb5_init_context)
+        return 0;
+
     if ( IsDebuggerPresent() ) {
         OutputDebugString("KFW_AFS_get_cred for token ");
         OutputDebugString(username);
@@ -1262,6 +1287,9 @@ KFW_AFS_destroy_tickets_for_cell(char * cell)
     int count;
     char ** principals = NULL;
 
+    if (!pkrb5_init_context)
+        return 0;
+
     if ( IsDebuggerPresent() ) {
         OutputDebugString("KFW_AFS_destroy_ticets_for_cell: ");
         OutputDebugString(cell);
@@ -1316,7 +1344,7 @@ KFW_AFS_destroy_tickets_for_cell(char * cell)
 }
 
 int
-KFW_AFS_renew_expiring_credentials(void)
+KFW_AFS_renew_expiring_tokens(void)
 {
     krb5_error_code                    code = 0;
     krb5_context                       ctx = 0;
@@ -1329,11 +1357,14 @@ KFW_AFS_renew_expiring_credentials(void)
     char local_cell[MAXCELLCHARS+1]="";
     afsconf_cell cellconfig;
 
+    if (!pkrb5_init_context)
+        return 0;
+
     if ( pcc_next == NULL ) // nothing to do
         return 0;
 
     if ( IsDebuggerPresent() ) {
-        OutputDebugString("KFW_AFS_renew_expiring_credentials\n");
+        OutputDebugString("KFW_AFS_renew_expiring_tokens\n");
     }
 
     code = pkrb5_init_context(&ctx);
@@ -1422,6 +1453,9 @@ KFW_AFS_renew_token_for_cell(char * cell)
     int count;
     char ** principals = NULL;
 
+    if (!pkrb5_init_context)
+        return 0;
+
     if ( IsDebuggerPresent() ) {
         OutputDebugString("KFW_AFS_renew_token_for_cell:");
         OutputDebugString(cell);
@@ -1435,7 +1469,9 @@ KFW_AFS_renew_token_for_cell(char * cell)
     if ( count > 0 ) {
         krb5_principal      princ = 0;
         krb5_principal      service = 0;
+#ifdef COMMENT
         krb5_creds          mcreds, creds;
+#endif /* COMMENT */
         krb5_ccache                    cc  = 0;
         const char * realm = NULL;
         afsconf_cell cellconfig;
@@ -1458,6 +1494,10 @@ KFW_AFS_renew_token_for_cell(char * cell)
                 OutputDebugString("\n");
             }
 
+#ifdef COMMENT
+            /* krb5_cc_remove_cred() is not implemented 
+             * for a single cred 
+             */
             code = pkrb5_build_principal(ctx, &service, strlen(realm),
                                           realm, "afs", cell, NULL);
             if (!code) {
@@ -1485,6 +1525,8 @@ KFW_AFS_renew_token_for_cell(char * cell)
                     pkrb5_free_principal(ctx, creds.server);
                 }
             }
+#endif /* COMMENT */
+
             code = KFW_AFS_klog(ctx, cc, "afs", cell, (char *)realm, pLeash_get_default_lifetime());
             if ( IsDebuggerPresent() ) {
                 char message[256];
@@ -1548,6 +1590,9 @@ KFW_renew(krb5_context alt_ctx, krb5_ccache alt_cc)
     krb5_creds                         my_creds;
     krb5_data                   *realm = 0;
 
+    if (!pkrb5_init_context)
+        return 0;
+
        memset(&my_creds, 0, sizeof(krb5_creds));
 
     if ( alt_ctx ) {
@@ -1825,6 +1870,9 @@ KFW_kdestroy(krb5_context alt_ctx, krb5_ccache alt_cc)
     krb5_ccache                        cc;
     krb5_error_code            code;
 
+    if (!pkrb5_init_context)
+        return 0;
+
     if (alt_ctx)
     {
         ctx = alt_ctx;
@@ -2327,6 +2375,160 @@ KFW_AFS_unlog(void)
     return(0);
 }
 
+
+#define TKTLIFENUMFIXED 64
+#define TKTLIFEMINFIXED 0x80
+#define TKTLIFEMAXFIXED 0xBF
+#define TKTLIFENOEXPIRE 0xFF
+#define MAXTKTLIFETIME (30*24*3600)    /* 30 days */
+#ifndef NEVERDATE
+#define NEVERDATE ((unsigned long)0x7fffffffL)
+#endif
+
+static int no_long_lifetimes = 0;
+typedef unsigned long u_int32_t;
+
+static const int tkt_lifetimes[TKTLIFENUMFIXED] = {
+    38400,                             /* 10.67 hours, 0.44 days */ 
+    41055,                             /* 11.40 hours, 0.48 days */ 
+    43894,                             /* 12.19 hours, 0.51 days */ 
+    46929,                             /* 13.04 hours, 0.54 days */ 
+    50174,                             /* 13.94 hours, 0.58 days */ 
+    53643,                             /* 14.90 hours, 0.62 days */ 
+    57352,                             /* 15.93 hours, 0.66 days */ 
+    61318,                             /* 17.03 hours, 0.71 days */ 
+    65558,                             /* 18.21 hours, 0.76 days */ 
+    70091,                             /* 19.47 hours, 0.81 days */ 
+    74937,                             /* 20.82 hours, 0.87 days */ 
+    80119,                             /* 22.26 hours, 0.93 days */ 
+    85658,                             /* 23.79 hours, 0.99 days */ 
+    91581,                             /* 25.44 hours, 1.06 days */ 
+    97914,                             /* 27.20 hours, 1.13 days */ 
+    104684,                            /* 29.08 hours, 1.21 days */ 
+    111922,                            /* 31.09 hours, 1.30 days */ 
+    119661,                            /* 33.24 hours, 1.38 days */ 
+    127935,                            /* 35.54 hours, 1.48 days */ 
+    136781,                            /* 37.99 hours, 1.58 days */ 
+    146239,                            /* 40.62 hours, 1.69 days */ 
+    156350,                            /* 43.43 hours, 1.81 days */ 
+    167161,                            /* 46.43 hours, 1.93 days */ 
+    178720,                            /* 49.64 hours, 2.07 days */ 
+    191077,                            /* 53.08 hours, 2.21 days */ 
+    204289,                            /* 56.75 hours, 2.36 days */ 
+    218415,                            /* 60.67 hours, 2.53 days */ 
+    233517,                            /* 64.87 hours, 2.70 days */ 
+    249664,                            /* 69.35 hours, 2.89 days */ 
+    266926,                            /* 74.15 hours, 3.09 days */ 
+    285383,                            /* 79.27 hours, 3.30 days */ 
+    305116,                            /* 84.75 hours, 3.53 days */ 
+    326213,                            /* 90.61 hours, 3.78 days */ 
+    348769,                            /* 96.88 hours, 4.04 days */ 
+    372885,                            /* 103.58 hours, 4.32 days */ 
+    398668,                            /* 110.74 hours, 4.61 days */ 
+    426234,                            /* 118.40 hours, 4.93 days */ 
+    455705,                            /* 126.58 hours, 5.27 days */ 
+    487215,                            /* 135.34 hours, 5.64 days */ 
+    520904,                            /* 144.70 hours, 6.03 days */ 
+    556921,                            /* 154.70 hours, 6.45 days */ 
+    595430,                            /* 165.40 hours, 6.89 days */ 
+    636601,                            /* 176.83 hours, 7.37 days */ 
+    680618,                            /* 189.06 hours, 7.88 days */ 
+    727680,                            /* 202.13 hours, 8.42 days */ 
+    777995,                            /* 216.11 hours, 9.00 days */ 
+    831789,                            /* 231.05 hours, 9.63 days */ 
+    889303,                            /* 247.03 hours, 10.29 days */
+
+    950794,                            /* 264.11 hours, 11.00 days */
+
+    1016537,                           /* 282.37 hours, 11.77 days */
+
+    1086825,                           /* 301.90 hours, 12.58 days */
+
+    1161973,                           /* 322.77 hours, 13.45 days */
+
+    1242318,                           /* 345.09 hours, 14.38 days */
+
+    1328218,                           /* 368.95 hours, 15.37 days */
+
+    1420057,                           /* 394.46 hours, 16.44 days */
+
+    1518247,                           /* 421.74 hours, 17.57 days */
+
+    1623226,                           /* 450.90 hours, 18.79 days */
+
+    1735464,                           /* 482.07 hours, 20.09 days */
+
+    1855462,                           /* 515.41 hours, 21.48 days */
+
+    1983758,                           /* 551.04 hours, 22.96 days */
+
+    2120925,                           /* 589.15 hours, 24.55 days */
+
+    2267576,                           /* 629.88 hours, 26.25 days */
+
+    2424367,                           /* 673.44 hours, 28.06 days */
+
+    2592000};                          /* 720.00 hours, 30.00 days */
+
+
+/*
+ * KFW_KRB4_life_to_time - takes a start time and a Kerberos standard
+ * lifetime char and returns the corresponding end time.  There are
+ * four simple cases to be handled.  The first is a life of 0xff,
+ * meaning no expiration, and results in an end time of 0xffffffff.
+ * The second is when life is less than the values covered by the
+ * table.  In this case, the end time is the start time plus the
+ * number of 5 minute intervals specified by life.  The third case
+ * returns start plus the MAXTKTLIFETIME if life is greater than
+ * TKTLIFEMAXFIXED.  The last case, uses the life value (minus
+ * TKTLIFEMINFIXED) as an index into the table to extract the lifetime
+ * in seconds, which is added to start to produce the end time.
+ */
+static u_int32_t
+KFW_KRB4_life_to_time(u_int32_t start, int life_)
+{
+    unsigned char life = (unsigned char) life_;
+
+    if (no_long_lifetimes) return start + life*5*60;
+
+    if (life == TKTLIFENOEXPIRE) return NEVERDATE;
+    if (life < TKTLIFEMINFIXED) return start + life*5*60;
+    if (life > TKTLIFEMAXFIXED) return start + MAXTKTLIFETIME;
+    return start + tkt_lifetimes[life - TKTLIFEMINFIXED];
+}
+
+/*
+ * KFW_KRB4_time_to_life - takes start and end times for the ticket and
+ * returns a Kerberos standard lifetime char, possibily using the
+ * tkt_lifetimes table for lifetimes above 127*5 minutes.  First, the
+ * special case of (end == NEVERDATE) is handled to mean no
+ * expiration.  Then negative lifetimes and those greater than the
+ * maximum ticket lifetime are rejected.  Then lifetimes less than the
+ * first table entry are handled by rounding the requested lifetime
+ * *up* to the next 5 minute interval.  The final step is to search
+ * the table for the smallest entry *greater than or equal* to the
+ * requested entry.
+ */
+static int 
+KFW_KRB4_time_to_life(u_int32_t start, u_int32_t end)
+{
+    int i;
+    long lifetime = end - start;
+
+    if (no_long_lifetimes) return (lifetime + 5*60 - 1)/(5*60);
+
+    if (end >= NEVERDATE) return TKTLIFENOEXPIRE;
+    if (lifetime > MAXTKTLIFETIME || lifetime <= 0) return 0;
+    if (lifetime < tkt_lifetimes[0]) return (lifetime + 5*60 - 1)/(5*60);
+    for (i=0; i<TKTLIFENUMFIXED; i++) {
+       if (lifetime <= tkt_lifetimes[i]) {
+           return i+TKTLIFEMINFIXED;
+       }
+    }
+    return 0;
+}
+
+
 int
 KFW_AFS_klog(
     krb5_context alt_ctx,
@@ -2378,6 +2580,9 @@ KFW_AFS_klog(
         return(-2);
     }
 
+    if (!pkrb5_init_context)
+        return 0;
+
     memset(RealmName, '\0', sizeof(RealmName));
     memset(CellName, '\0', sizeof(CellName));
     memset(ServiceName, '\0', sizeof(ServiceName));
@@ -2477,7 +2682,7 @@ KFW_AFS_klog(
             char * cname, *sname;
             pkrb5_unparse_name(ctx, increds.client, &cname);
             pkrb5_unparse_name(ctx, increds.server, &sname);
-            OutputDebugString("Getting credentials for \"");
+            OutputDebugString("Getting tickets for \"");
             OutputDebugString(cname);
             OutputDebugString("\" and service \"");
             OutputDebugString(sname);
@@ -2503,7 +2708,7 @@ KFW_AFS_klog(
                 pkrb5_unparse_name(ctx, increds.client, &cname);
                 pkrb5_unparse_name(ctx, increds.server, &sname);
                 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
-                OutputDebugString("Trying again: getting credentials for \"");
+                OutputDebugString("Trying again: getting tickets for \"");
                 OutputDebugString(cname);
                 OutputDebugString("\" and service \"");
                 OutputDebugString(sname);
@@ -2589,7 +2794,7 @@ KFW_AFS_klog(
     memset(&atoken, '\0', sizeof(atoken));
     atoken.kvno = creds.kvno;
     atoken.startTime = creds.issue_date;
-    atoken.endTime = creds.issue_date + (creds.lifetime * 300);
+    atoken.endTime = creds.issue_date + KFW_KRB4_life_to_time(0,creds.lifetime);
     memcpy(&atoken.sessionKey, creds.session, 8);
     atoken.ticketLen = creds.ticket_st.length;
     memcpy(atoken.ticket, creds.ticket_st.dat, atoken.ticketLen);
@@ -2658,6 +2863,9 @@ afs_realm_of_cell(afsconf_cell *cellconfig)
     if (!cellconfig)
         return 0;
 
+    if (!pkrb5_init_context)
+        return 0;
+
     r = pkrb5_init_context(&ctx); 
     if ( !r )
         r = pkrb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist);
@@ -3032,7 +3240,7 @@ ObtainTokensFromUserIfNeeded(HWND hWnd)
     struct ktc_principal    aserver;
     struct ktc_principal    aclient;
     struct ktc_token   atoken;
-    krb5_context ctx;
+    krb5_context ctx = 0;
     krb5_timestamp now = 0;
     krb5_error_code code;
     int serverReachable = 0;
@@ -3045,6 +3253,7 @@ ObtainTokensFromUserIfNeeded(HWND hWnd)
 #endif /* USE_FSPROBE */
     DWORD       CurrentState;
     char        HostName[64];
+    int         use_kfw = KFW_is_available();
 
     CurrentState = 0;
     memset(HostName, '\0', sizeof(HostName));
@@ -3056,7 +3265,10 @@ ObtainTokensFromUserIfNeeded(HWND hWnd)
         return;
     }
 
-    if ( KFW_is_available() ) {
+    if (!pkrb5_init_context)
+        return;
+
+    if ( use_kfw ) {
         code = pkrb5_init_context(&ctx);
         if ( code ) goto cleanup;
     }
@@ -3073,13 +3285,20 @@ ObtainTokensFromUserIfNeeded(HWND hWnd)
 
     rc = pktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient);
 
-    if ( KFW_is_available() ) {
+    if ( use_kfw ) {
         code = pkrb5_timeofday(ctx, &now);
         if ( code ) 
             now = 0;
 
         if (!rc && (now < atoken.endTime))
             goto cleanup;
+
+        if ( IsDebuggerPresent() ) {
+            char message[256];
+            sprintf(message,"KFW_AFS_klog() returns: %d  now = %ul  endTime = %ul\n",
+                     rc, now, atoken.endTime);
+            OutputDebugString(message);
+        }
     } else {
         SYSTEMTIME stNow;
         FILETIME ftNow;
@@ -3101,13 +3320,20 @@ ObtainTokensFromUserIfNeeded(HWND hWnd)
 
         if (!rc && (llNow < llExpires))
             goto cleanup;
+
+        if ( IsDebuggerPresent() ) {
+            char message[256];
+            sprintf(message,"KFW_AFS_klog() returns: %d  now = %ul  endTime = %ul\n",
+                     rc, llNow, llExpires);
+            OutputDebugString(message);
+        }
     }
 
 
 #ifdef USE_FSPROBE
     serverReachable = cellPing(NULL);
 #else
-    if ( KFW_is_available() ) {
+    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
@@ -3163,14 +3389,20 @@ ObtainTokensFromUserIfNeeded(HWND hWnd)
         serverReachable = 1;
     }
 #endif
-    if ( !serverReachable )
+    if ( !serverReachable ) {
+        if ( IsDebuggerPresent() )
+            OutputDebugString("Server Unreachable\n");
         goto cleanup;
+    }
+
+    if ( IsDebuggerPresent() )
+        OutputDebugString("Server Reachable\n");
 
-    if ( KFW_is_available() ) {
+    if ( use_kfw ) {
 #ifdef USE_MS2MIT
         KFW_import_windows_lsa();
 #endif /* USE_MS2MIT */
-        KFW_AFS_renew_expiring_credentials();
+        KFW_AFS_renew_expiring_tokens();
         KFW_AFS_renew_token_for_cell(rootcell);
 
         rc = pktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient);
@@ -3186,6 +3418,7 @@ ObtainTokensFromUserIfNeeded(HWND hWnd)
         GlobalFree(rootcell);
 
 #ifndef USE_FSPROBE
+       if (KFW_is_available()) {
     if ( pname )
         pkrb5_free_unparsed_name(ctx,pname);
     if ( principal )
@@ -3195,6 +3428,7 @@ ObtainTokensFromUserIfNeeded(HWND hWnd)
 #endif /* USE_FSPROBE */
     if (ctx)
         pkrb5_free_context(ctx);
+       }
     return;
 }
 
@@ -3215,9 +3449,11 @@ GetNumOfIpAddrs(void)
     if (code == ERROR_INSUFFICIENT_BUFFER) {
         pIpAddrTable = malloc(dwSize);
         code = GetIpAddrTable(pIpAddrTable, &dwSize, 0);
-        for ( index=0; index < pIpAddrTable->dwNumEntries; index++ ) {
-            if (pIpAddrTable->table[index].dwAddr != 0)
-                validAddrs++;
+        if ( code == NO_ERROR ) {
+            for ( index=0; index < pIpAddrTable->dwNumEntries; index++ ) {
+                if (pIpAddrTable->table[index].dwAddr != 0)
+                    validAddrs++;
+            }
         }
         free(pIpAddrTable);
     }
@@ -3228,12 +3464,13 @@ void
 IpAddrChangeMonitor(void * hWnd)
 {
 #ifdef USE_OVERLAPPED
-    HANDLE Handle = INVALID_HANDLE_VALUE;
+    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;
@@ -3245,30 +3482,53 @@ IpAddrChangeMonitor(void * hWnd)
         Result = NotifyAddrChange(&Handle,&Ovlap);
         if (Result != ERROR_IO_PENDING)
         {        
-            printf("NotifyAddrChange() failed with error %d \n", Result);
+            if ( IsDebuggerPresent() ) {
+                sprintf(message, "NotifyAddrChange() failed with error %d \n", Result);
+                OutputDebugString(message);
+            }
             break;
         }
 
-        if ((Result = WaitForSingleObject(Handle,INFINITE)) == WAIT_FAILED)
+        if ((Result = WaitForSingleObject(Handle,INFINITE)) != WAIT_OBJECT_0)
         {
-            printf("WaitForSingleObject() failed with error %d\n",
-                    GetLastError());
+            if ( IsDebuggerPresent() ) {
+                sprintf(message, "WaitForSingleObject() failed with error %d\n",
+                        GetLastError());
+                OutputDebugString(message);
+            }
             continue;
         }
 
         if (GetOverlappedResult(Handle, &Ovlap,
                                  &DataTransfered, TRUE) == 0)
         {
-            printf("GetOverlapped result failed %d \n",
-                    GetLastError());
+            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
@@ -3278,11 +3538,6 @@ IpAddrChangeMonitor(void * hWnd)
         }
         prevNumOfAddrs = NumOfAddrs;
     }
-
-#ifdef USE_OVERLAPPED
-    if (Handle != INVALID_HANDLE_VALUE)
-        CloseHandle(Handle);
-#endif 
 }