windows-netidmgr-cell-search-registry-20090616
[openafs.git] / src / WINNT / netidmgr_plugin / afsfuncs.c
index 66eab2a..05018c8 100644 (file)
 #pragma warning (push)
 #pragma warning (disable: 4005)
 
+#include<winsock2.h>
 #include<afscred.h>
+#include<afs/cm.h>
 #include<dynimport.h>
 #include<krb5common.h>
 
 #pragma warning (pop)
 
+static char *afs_realm_of_cell(afs_conf_cell *, BOOL);
+static long afs_get_cellconfig_callback(void *, struct sockaddr_in *, char *, unsigned short ipRank);
+static int afs_get_cellconfig(char *, afs_conf_cell *, char *);
+
 BOOL
 afs_is_running(void) {
     DWORD CurrentState;
@@ -728,14 +734,15 @@ afs_klog(khm_handle identity,
          char *realm,
          int LifeTime,
          afs_tk_method method,
-         time_t * tok_expiration) {
+         time_t * tok_expiration,
+         char *linkedCell) {
 
     long       rc;
     CREDENTIALS        creds;
     struct ktc_principal       aserver;
     struct ktc_principal       aclient;
-    char       realm_of_user[REALM_SZ]; /* Kerberos realm of user */
-    char       realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
+    char       realm_of_user[MAXKTCREALMLEN]; /* Kerberos realm of user */
+    char       realm_of_cell[MAXKTCREALMLEN]; /* Kerberos realm of cell */
     char       local_cell[MAXCELLCHARS+1];
     char       Dmycell[MAXCELLCHARS+1];
     struct ktc_token   atoken;
@@ -763,6 +770,7 @@ afs_klog(khm_handle identity,
     if ( !cell )    cell = "";
     if ( !service ) service = "";
 
+    memset(&ak_cellconfig, 0, sizeof(ak_cellconfig));
     memset(RealmName, '\0', sizeof(RealmName));
     memset(CellName, '\0', sizeof(CellName));
     memset(ServiceName, '\0', sizeof(ServiceName));
@@ -784,6 +792,10 @@ afs_klog(khm_handle identity,
         return(rc);
     }
 
+    if (linkedCell && ak_cellconfig.linkedCell)
+        StringCbCopyA(linkedCell, MAXCELLCHARS, 
+                      ak_cellconfig.linkedCell);
+
     StringCbCopyA(realm_of_cell, sizeof(realm_of_cell), 
                   afs_realm_of_cell(&ak_cellconfig, FALSE));
 
@@ -831,8 +843,8 @@ afs_klog(khm_handle identity,
 
             pkrb5_cc_get_principal(context, k5cc, &client_principal);
             i = krb5_princ_realm(context, client_principal)->length;
-            if (i > REALM_SZ-1) 
-                i = REALM_SZ-1;
+            if (i > MAXKTCREALMLEN-1) 
+                i = MAXKTCREALMLEN-1;
             StringCchCopyNA(realm_of_user, ARRAYLENGTH(realm_of_user),
                             krb5_princ_realm(context, client_principal)->data,
                             i);
@@ -841,17 +853,6 @@ afs_klog(khm_handle identity,
             goto try_krb4;
         }
 
-        /* First try Service/Cell@REALM */
-        if (r = pkrb5_build_principal(context, &increds.server,
-                                         (int) strlen(RealmName),
-                                         RealmName,
-                                         ServiceName,
-                                         CellName,
-                                         0)) {
-            _reportf(L"krb5_build_principal returns %d", r);
-            goto end_krb5;
-        }
-
         increds.client = client_principal;
         increds.times.endtime = 0;
         /* Ask for DES since that is what V4 understands */
@@ -861,52 +862,147 @@ afs_klog(khm_handle identity,
         flags = KRB5_TC_OPENCLOSE;
         r = pkrb5_cc_set_flags(context, k5cc, flags);
 #endif
-      retry_retcred:
-        r = pkrb5_get_credentials(context, 0, k5cc, &increds, &k5creds);
-        if ((r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
-             r == KRB5KRB_ERR_GENERIC /* Heimdal */) &&
-            !RealmName[0]) {
-           StringCbCopyA(RealmName, sizeof(RealmName), 
-                         afs_realm_of_cell(&ak_cellconfig, TRUE));
-
-            pkrb5_free_principal(context, increds.server);
-           r = pkrb5_build_principal(context, &increds.server,
-                                        (int) strlen(RealmName),
-                                        RealmName,
-                                        ServiceName,
-                                        CellName,
-                                        0);
-            if (r == 0)
-                r = pkrb5_get_credentials(context, 0, k5cc, 
-                                          &increds, &k5creds);
-       }
-       if (r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
-            r == KRB5KRB_ERR_GENERIC /* Heimdal */) {
-            /* Next try Service@REALM */
-            pkrb5_free_principal(context, increds.server);
-            r = pkrb5_build_principal(context, &increds.server,
-                                         (int) strlen(RealmName),
-                                         RealmName,
-                                         ServiceName,
-                                         0);
-            if (r == 0)
-                r = pkrb5_get_credentials(context, 0, k5cc, 
-                                          &increds, &k5creds);
-        }
+        if (strlen(realm) != 0) {
+          retry_retcred_1:
+            /* First try Service/Cell@REALM */
+            if (r = pkrb5_build_principal(context, &increds.server,
+                                           (int) strlen(realm),
+                                           realm,
+                                           ServiceName,
+                                           CellName,
+                                           0)) {
+                _reportf(L"krb5_build_principal returns %d", r);
+                goto end_krb5;
+            }
 
-       /* Check to make sure we received a valid ticket; if not remove it
-       * and try again.  Perhaps there are two service tickets for the
-       * same service in the ccache.
-       */
-       if (r == 0 && k5creds && k5creds->times.endtime < time(NULL)) {
-           pkrb5_cc_remove_cred(context, k5cc, 0, k5creds);
-           pkrb5_free_creds(context, k5creds);
-           k5creds = NULL;
-           goto retry_retcred;
-       }
+            r = pkrb5_get_credentials(context, 0, k5cc, &increds, &k5creds);
+            if (r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
+                r == KRB5_ERR_HOST_REALM_UNKNOWN ||
+                r == KRB5KRB_ERR_GENERIC /* Heimdal */) {
+                /* Next try Service@REALM */
+                pkrb5_free_principal(context, increds.server);
+                r = pkrb5_build_principal(context, &increds.server,
+                                           (int) strlen(realm),
+                                           realm,
+                                           ServiceName,
+                                           0);
+                if (r == 0)
+                    r = pkrb5_get_credentials(context, 0, k5cc, 
+                                               &increds, &k5creds);
+            }
 
-        if (r == 0 && strlen(RealmName) == 0) 
-            copy_realm_of_ticket(context, realm_of_cell, sizeof(realm_of_cell), k5creds);
+            /* Check to make sure we received a valid ticket; if not remove it
+             * and try again.  Perhaps there are two service tickets for the
+             * same service in the ccache.
+             */
+            if (r == 0 && k5creds && k5creds->times.endtime < time(NULL)) {
+                pkrb5_free_principal(context, increds.server);
+                pkrb5_cc_remove_cred(context, k5cc, 0, k5creds);
+                pkrb5_free_creds(context, k5creds);
+                k5creds = NULL;
+                goto retry_retcred_1;
+            }
+        } else {
+          retry_retcred_2:
+            /* First try Service/Cell@_CLIENT_REALM */
+            if (r = pkrb5_build_principal(context, &increds.server,
+                                           (int) strlen(realm_of_user),
+                                           realm_of_user,
+                                           ServiceName,
+                                           CellName,
+                                           0)) {
+                _reportf(L"krb5_build_principal returns %d", r);
+                goto end_krb5;
+            }
+
+            r = pkrb5_get_credentials(context, 0, k5cc, &increds, &k5creds);
+            if (r == 0) {
+                /* the user realm is a valid cell realm */
+                StringCbCopyA(realm_of_cell, sizeof(realm_of_cell), realm_of_user);
+            }
+            if (r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
+                r == KRB5_ERR_HOST_REALM_UNKNOWN ||
+                r == KRB5KRB_ERR_GENERIC /* Heimdal */) {
+                pkrb5_free_principal(context, increds.server);
+                r = pkrb5_build_principal(context, &increds.server,
+                                           (int) strlen(realm_of_cell),
+                                           realm_of_cell,
+                                           ServiceName,
+                                           CellName,
+                                           0);
+                if (r == 0)
+                    r = pkrb5_get_credentials(context, 0, k5cc, 
+                                               &increds, &k5creds);
+            }
+            if ((r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
+                 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
+                 r == KRB5KRB_ERR_GENERIC /* Heimdal */) &&
+                 strlen(realm_of_cell) == 0) {
+                StringCbCopyA(realm_of_cell, sizeof(realm_of_cell), 
+                               afs_realm_of_cell(&ak_cellconfig, TRUE));
+
+                pkrb5_free_principal(context, increds.server);
+                r = pkrb5_build_principal(context, &increds.server,
+                                           (int) strlen(realm_of_cell),
+                                           realm_of_cell,
+                                           ServiceName,
+                                           CellName,
+                                           0);
+                if (r == 0)
+                    r = pkrb5_get_credentials(context, 0, k5cc, 
+                                               &increds, &k5creds);
+            }
+            if (r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
+                r == KRB5_ERR_HOST_REALM_UNKNOWN ||
+                r == KRB5KRB_ERR_GENERIC /* Heimdal */) {
+                /* Next try Service@REALM */
+                StringCbCopyA(realm_of_cell, sizeof(realm_of_cell), 
+                               afs_realm_of_cell(&ak_cellconfig, FALSE));
+
+                pkrb5_free_principal(context, increds.server);
+                r = pkrb5_build_principal(context, &increds.server,
+                                           (int) strlen(realm_of_cell),
+                                           realm_of_cell,
+                                           ServiceName,
+                                           0);
+                if (r == 0)
+                    r = pkrb5_get_credentials(context, 0, k5cc, 
+                                               &increds, &k5creds);
+            }
+            if ((r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
+                 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
+                 r == KRB5KRB_ERR_GENERIC /* Heimdal */) &&
+                 strlen(realm_of_cell) == 0) {
+                /* Next try Service@REALM */
+                StringCbCopyA(realm_of_cell, sizeof(realm_of_cell), 
+                               afs_realm_of_cell(&ak_cellconfig, TRUE));
+
+                pkrb5_free_principal(context, increds.server);
+                r = pkrb5_build_principal(context, &increds.server,
+                                           (int) strlen(realm_of_cell),
+                                           realm_of_cell,
+                                           ServiceName,
+                                           0);
+                if (r == 0)
+                    r = pkrb5_get_credentials(context, 0, k5cc, 
+                                               &increds, &k5creds);
+            }
+
+            if (r == 0 && strlen(realm_of_cell) == 0) 
+                copy_realm_of_ticket(context, realm_of_cell, sizeof(realm_of_cell), k5creds);
+
+            /* Check to make sure we received a valid ticket; if not remove it
+             * and try again.  Perhaps there are two service tickets for the
+             * same service in the ccache.
+             */
+            if (r == 0 && k5creds && k5creds->times.endtime < time(NULL)) {
+                pkrb5_free_principal(context, increds.server);
+                pkrb5_cc_remove_cred(context, k5cc, 0, k5creds);
+                pkrb5_free_creds(context, k5creds);
+                k5creds = NULL;
+                goto retry_retcred_2;
+            }
+        }
 
         pkrb5_free_principal(context, increds.server);
         pkrb5_free_principal(context, client_principal);
@@ -977,7 +1073,8 @@ afs_klog(khm_handle identity,
 
             _reportf(L"Same token already exists");
             
-            return 0;
+            rc = 0;
+            goto cleanup;
         }
 
         // * Reset the "aclient" structure before we call ktc_SetToken.
@@ -1021,7 +1118,7 @@ afs_klog(khm_handle identity,
             if (context)
                 pkrb5_free_context(context);
             
-            return 0;
+            goto cleanup;
         }
 
         _reportf(L"SetToken returns code %d", rc);
@@ -1067,6 +1164,7 @@ afs_klog(khm_handle identity,
         _reportf(L"Kerberos 4 not configured");
 
     if (!bGotCreds && supports_krb4 && 
+        strlen(RealmName) < REALM_SZ && 
         (method == AFS_TOKEN_AUTO ||
          method == AFS_TOKEN_KRB4)) {
 
@@ -1154,7 +1252,8 @@ afs_klog(khm_handle identity,
             !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) {
 
             /* success! */
-            return(0);
+            rc = 0;
+            goto cleanup;
         }
 
         // Reset the "aclient" structure before we call ktc_SetToken.
@@ -1179,7 +1278,7 @@ afs_klog(khm_handle identity,
 
         if (rc = ktc_SetToken(&aserver, &atoken, &aclient, 0)) {
             afs_report_error(rc, "ktc_SetToken()");
-            return(rc);
+            goto cleanup;
         }
     } else if (method == AFS_TOKEN_AUTO ||
                method >= AFS_TOKEN_USER) {
@@ -1209,6 +1308,10 @@ afs_klog(khm_handle identity,
         }
     }
 
+  cleanup:
+    if (ak_cellconfig.linkedCell)
+        free(ak_cellconfig.linkedCell);
+
     return rc;
 }
 
@@ -1219,7 +1322,7 @@ static char *
 afs_realm_of_cell(afs_conf_cell *cellconfig, BOOL referral_fallback)
 {
     char krbhst[MAX_HSTNM]="";
-    static char krbrlm[REALM_SZ+1]="";
+    static char krbrlm[MAXKTCREALMLEN+1]="";
     krb5_context  ctx = 0;
     char ** realmlist=NULL;
     krb5_error_code r = 0;
@@ -1285,7 +1388,8 @@ static int
 afs_get_cellconfig(char *cell, afs_conf_cell *cellconfig, char *local_cell)
 {
     int        rc;
-    int ttl;
+    int ttl = 0;
+    char linkedCell[MAXCELLCHARS]="";
 
     local_cell[0] = (char)0;
     memset(cellconfig, 0, sizeof(*cellconfig));
@@ -1300,16 +1404,21 @@ afs_get_cellconfig(char *cell, afs_conf_cell *cellconfig, char *local_cell)
     if (strlen(cell) == 0)
         StringCbCopyA(cell, (MAXCELLCHARS+1) * sizeof(char), local_cell);
 
-    /* WIN32: cm_SearchCellFile(cell, pcallback, pdata) */
     StringCbCopyA(cellconfig->name, (MAXCELLCHARS+1) * sizeof(char), cell);
 
-    rc = cm_SearchCellFile(cell, NULL, afs_get_cellconfig_callback, 
-                           (void*)cellconfig);
+    rc = cm_SearchCellRegistry(1, cell, NULL, linkedCell, 
+                               afs_get_cellconfig_callback, (void*) cellconfig);
+    if (rc && rc != CM_ERROR_FORCE_DNS_LOOKUP)
+        rc = cm_SearchCellFileEx(cell, NULL, linkedCell, afs_get_cellconfig_callback, 
+                                 (void*)cellconfig);
     if(rc)
         rc = cm_SearchCellByDNS(cell, NULL, &ttl, 
                                 afs_get_cellconfig_callback, 
                                 (void*) cellconfig);
 
+    if (linkedCell[0])
+        cellconfig->linkedCell = strdup(linkedCell);
+
     return rc;
 }
 
@@ -1319,7 +1428,8 @@ afs_get_cellconfig(char *cell, afs_conf_cell *cellconfig, char *local_cell)
 static long 
 afs_get_cellconfig_callback(void *cellconfig, 
                             struct sockaddr_in *addrp, 
-                            char *namep)
+                            char *namep,
+                            unsigned short ipRank)
 {
     afs_conf_cell *cc = (afs_conf_cell *)cellconfig;
 
@@ -1508,14 +1618,17 @@ afs_check_for_cell_realm_match(khm_handle identity, char * cell) {
     int rc;
 
     ZeroMemory(local_cell, sizeof(local_cell));
+    ZeroMemory(&cellconfig, sizeof(cellconfig));
 
     rc = afs_get_cellconfig(cell, &cellconfig, local_cell);
     if (rc)
         return FALSE;
 
     realm = afs_realm_of_cell(&cellconfig, FALSE);
-    if (realm == NULL)
-        return FALSE;
+    if (cellconfig.linkedCell)
+        free(cellconfig.linkedCell);
+    if (!realm[0])      /* referral; assume it matches */
+        return TRUE;
 
     AnsiStrToUnicode(wrealm, sizeof(wrealm), realm);