registry-call-optimizations-20040313
[openafs.git] / src / WINNT / client_creds / afskfw.c
index 92a902b..0e2e03e 100644 (file)
@@ -419,7 +419,7 @@ KFW_initialize(void)
             KFW_import_windows_lsa();
 #endif /* USE_MS2MIT */
             KFW_import_ccache_data();
-                   KFW_AFS_renew_expiring_credentials();
+                   KFW_AFS_renew_expiring_tokens();
 
             /* WIN32 NOTE: no way to get max chars */
             if (!pcm_GetRootCellName(rootcell))
@@ -457,9 +457,33 @@ KFW_cleanup(void)
         FreeLibrary(hCCAPI);
 }
 
+static char OpenAFSConfigKeyName[] = "SOFTWARE\\OpenAFS\\Client";
+
 int 
 KFW_is_available(void)
 {
+    HKEY parmKey;
+       DWORD code, len;
+    DWORD enableKFW = 1;
+
+    code = RegOpenKeyEx(HKEY_CURRENT_USER, OpenAFSConfigKeyName,
+                         0, KEY_QUERY_VALUE, &parmKey);
+    if (code != ERROR_SUCCESS)
+        code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, OpenAFSConfigKeyName,
+                             0, KEY_QUERY_VALUE, &parmKey);
+       if (code == ERROR_SUCCESS) {
+        len = sizeof(enableKFW);
+        code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
+                                (BYTE *) &enableKFW, &len);
+        if (code != ERROR_SUCCESS) {
+            enableKFW = 1;
+        }
+        RegCloseKey (parmKey);
+       }
+
+    if ( !enableKFW )
+        return FALSE;
+
     KFW_initialize();
     if ( hKrb5 && hComErr && hService && 
 #ifdef USE_MS2MIT
@@ -1292,7 +1316,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;
@@ -1309,7 +1333,7 @@ KFW_AFS_renew_expiring_credentials(void)
         return 0;
 
     if ( IsDebuggerPresent() ) {
-        OutputDebugString("KFW_AFS_renew_expiring_credentials\n");
+        OutputDebugString("KFW_AFS_renew_expiring_tokens\n");
     }
 
     code = pkrb5_init_context(&ctx);
@@ -1434,6 +1458,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) {
@@ -1461,6 +1489,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];
@@ -2303,6 +2333,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,
@@ -2453,7 +2637,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);
@@ -2479,7 +2663,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);
@@ -2565,7 +2749,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);
@@ -3008,7 +3192,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;
@@ -3021,6 +3205,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));
@@ -3032,7 +3217,7 @@ ObtainTokensFromUserIfNeeded(HWND hWnd)
         return;
     }
 
-    if ( KFW_is_available() ) {
+    if ( use_kfw ) {
         code = pkrb5_init_context(&ctx);
         if ( code ) goto cleanup;
     }
@@ -3049,13 +3234,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;
@@ -3077,13 +3269,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
@@ -3139,14 +3338,20 @@ ObtainTokensFromUserIfNeeded(HWND hWnd)
         serverReachable = 1;
     }
 #endif
-    if ( !serverReachable )
+    if ( !serverReachable ) {
+        if ( IsDebuggerPresent() )
+            OutputDebugString("Server Unreachable\n");
         goto cleanup;
+    }
 
-    if ( KFW_is_available() ) {
+    if ( IsDebuggerPresent() )
+        OutputDebugString("Server Reachable\n");
+
+    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);
@@ -3162,6 +3367,7 @@ ObtainTokensFromUserIfNeeded(HWND hWnd)
         GlobalFree(rootcell);
 
 #ifndef USE_FSPROBE
+       if (KFW_is_available()) {
     if ( pname )
         pkrb5_free_unparsed_name(ctx,pname);
     if ( principal )
@@ -3171,6 +3377,7 @@ ObtainTokensFromUserIfNeeded(HWND hWnd)
 #endif /* USE_FSPROBE */
     if (ctx)
         pkrb5_free_context(ctx);
+       }
     return;
 }
 
@@ -3245,6 +3452,14 @@ IpAddrChangeMonitor(void * hWnd)
 #endif
         
         NumOfAddrs = GetNumOfIpAddrs();
+
+        if ( IsDebuggerPresent() ) {
+            char message[256];
+            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