windows-getrootcellname-20090223
[openafs.git] / src / WINNT / afsd / afskfw.c
index da84abd..7653574 100644 (file)
@@ -447,7 +447,7 @@ KFW_initialize(void)
             LoadFuncs(CCAPI_DLL, ccapi_fi, &hCCAPI, 0, 1, 0, 0);
 
             if ( KFW_is_available() ) {
-                char rootcell[MAXCELLCHARS+1];
+                char rootcell[CELL_MAXNAMELEN+1];
 #ifdef USE_MS2MIT
                 KFW_import_windows_lsa();
 #endif /* USE_MS2MIT */
@@ -667,11 +667,11 @@ KRB5_error(krb5_error_code rc, LPCSTR FailedFunctionName,
         {
             if (cache && *cache != NULL) {
                 pkrb5_cc_close(*ctx, *cache);
-                               *cache = NULL;
-                       }
+                *cache = NULL;
+            }
        
             pkrb5_free_context(*ctx);
-                       *ctx = NULL;
+            *ctx = NULL;
         }
     }
 
@@ -1324,7 +1324,7 @@ KFW_AFS_get_cred( char * username,
     krb5_principal principal = NULL;
     char * pname = NULL;
     krb5_error_code code;
-    char local_cell[MAXCELLCHARS+1];
+    char local_cell[CELL_MAXNAMELEN+1];
     char **cells = NULL;
     int  cell_count=0;
     struct afsconf_cell cellconfig;
@@ -1341,6 +1341,8 @@ KFW_AFS_get_cred( char * username,
         OutputDebugString("\n");
     }
 
+    memset(&cellconfig, 0, sizeof(cellconfig));
+
     code = pkrb5_init_context(&ctx);
     if ( code ) goto cleanup;
 
@@ -1446,6 +1448,11 @@ KFW_AFS_get_cred( char * username,
                     sprintf(message,"found another cell for the same principal: %s\n",cell);
                     OutputDebugString(message);
                 }
+
+                if (cellconfig.linkedCell) {
+                    free(cellconfig.linkedCell);
+                    cellconfig.linkedCell = NULL;
+                }
                 code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
                 if ( code ) continue;
     
@@ -1476,6 +1483,8 @@ KFW_AFS_get_cred( char * username,
         free(pname);
     if ( cc )
         pkrb5_cc_close(ctx, cc);
+    if ( cellconfig.linkedCell )
+        free(cellconfig.linkedCell);
 
     if ( code && reasonP ) {
         *reasonP = (char *)perror_message(code);
@@ -1614,7 +1623,7 @@ KFW_AFS_renew_expiring_tokens(void)
     int cell_count;
     char ** cells=NULL;
     const char * realm = NULL;
-    char local_cell[MAXCELLCHARS+1]="";
+    char local_cell[CELL_MAXNAMELEN+1]="";
     struct afsconf_cell cellconfig;
 
     if (!pkrb5_init_context)
@@ -1627,6 +1636,8 @@ KFW_AFS_renew_expiring_tokens(void)
         OutputDebugString("KFW_AFS_renew_expiring_tokens\n");
     }
 
+    memset(&cellconfig, 0, sizeof(cellconfig));
+
     code = pkrb5_init_context(&ctx);
     if (code) goto cleanup;
 
@@ -1668,6 +1679,10 @@ KFW_AFS_renew_expiring_tokens(void)
                         OutputDebugString(cells[cell_count]);
                         OutputDebugString("\n");
                     }
+                    if (cellconfig.linkedCell) {
+                        free(cellconfig.linkedCell);
+                        cellconfig.linkedCell = NULL;
+                    }
                     code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
                     if ( code ) continue;
                     realm = afs_realm_of_cell(ctx, &cellconfig);  // do not free
@@ -1700,6 +1715,8 @@ KFW_AFS_renew_expiring_tokens(void)
         pkrb5_cc_close(ctx,cc);
     if ( ctx )
         pkrb5_free_context(ctx);
+    if (cellconfig.linkedCell)
+        free(cellconfig.linkedCell);
 
     return 0;
 }
@@ -1742,7 +1759,9 @@ KFW_AFS_renew_token_for_cell(char * cell)
         krb5_ccache                    cc  = 0;
         const char * realm = NULL;
         struct afsconf_cell cellconfig;
-        char local_cell[MAXCELLCHARS+1];
+        char local_cell[CELL_MAXNAMELEN+1];
+
+        memset(&cellconfig, 0, sizeof(cellconfig));
 
         while ( count-- ) {
             code = pkrb5_parse_name(ctx, principals[count], &princ);
@@ -1751,6 +1770,10 @@ KFW_AFS_renew_token_for_cell(char * cell)
             code = KFW_get_ccache(ctx, princ, &cc);
             if (code) goto loop_cleanup;
 
+            if (cellconfig.linkedCell) {
+                free(cellconfig.linkedCell);
+                cellconfig.linkedCell = NULL;
+            }
             code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell);
             if ( code ) goto loop_cleanup;
 
@@ -1814,6 +1837,10 @@ KFW_AFS_renew_token_for_cell(char * cell)
                 pkrb5_free_principal(ctx, service);
                 princ = 0;
             }
+            if (cellconfig.linkedCell) {
+                free(cellconfig.linkedCell);
+                cellconfig.linkedCell = NULL;
+            }
 
             KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], code ? FALSE : TRUE);
             free(principals[count]);
@@ -1824,7 +1851,7 @@ KFW_AFS_renew_token_for_cell(char * cell)
 
   cleanup:
     if (ctx) 
-               pkrb5_free_context(ctx);
+        pkrb5_free_context(ctx);
     return (code ? FALSE : TRUE);
 
 }
@@ -2658,7 +2685,7 @@ ViceIDToUsername(char *username,
                  struct ktc_principal *aserver, 
                  struct ktc_token *atoken)
 {
-    static char lastcell[MAXCELLCHARS+1] = { 0 };
+    static char lastcell[CELL_MAXNAMELEN+1] = { 0 };
     static char confdir[512] = { 0 };
 #ifdef AFS_ID_TO_NAME
     char username_copy[BUFSIZ];
@@ -2734,6 +2761,25 @@ ViceIDToUsername(char *username,
 }
 
 
+static void
+copy_realm_of_ticket(krb5_context context, char * dest, size_t destlen, krb5_creds *v5cred) {
+    krb5_error_code code;
+    krb5_ticket *ticket;
+    size_t len;
+
+    code = pkrb5_decode_ticket(&v5cred->ticket, &ticket);
+    if (code == 0) {
+        len = krb5_princ_realm(context, ticket->server)->length;
+        if (len > destlen - 1)
+            len = destlen - 1;
+
+        strncpy(dest, krb5_princ_realm(context, ticket->server)->data, len);
+        dest[len] = '\0';
+
+        pkrb5_free_ticket(context, ticket);
+    }
+}
+
 int
 KFW_AFS_klog(
     krb5_context alt_ctx,
@@ -2754,8 +2800,8 @@ KFW_AFS_klog(
     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       local_cell[MAXCELLCHARS+1];
-    char       Dmycell[MAXCELLCHARS+1];
+    char       local_cell[CELL_MAXNAMELEN+1];
+    char       Dmycell[CELL_MAXNAMELEN+1];
     struct ktc_token   atoken;
     struct ktc_token   btoken;
     struct afsconf_cell        ak_cellconfig; /* General information about the cell */
@@ -2791,6 +2837,7 @@ KFW_AFS_klog(
     if (!pkrb5_init_context)
         return 0;
 
+    memset(&ak_cellconfig, 0, sizeof(ak_cellconfig));
     memset(RealmName, '\0', sizeof(RealmName));
     memset(CellName, '\0', sizeof(CellName));
     memset(ServiceName, '\0', sizeof(ServiceName));
@@ -2881,6 +2928,7 @@ KFW_AFS_klog(
     else
         strcpy(CellName, cell);
 
+    /* This is for Kerberos v4 only */
     if (strlen(realm) == 0)
         strcpy(RealmName, realm_of_cell);
     else
@@ -2890,56 +2938,31 @@ KFW_AFS_klog(
 
     if ( try_krb5 ) {
         int len;
+        code = KRB5KRB_ERR_GENERIC;
 
-        /* First try service/cell@REALM */
-        if (code = pkrb5_build_principal(ctx, &increds.server,
-                                          (int)strlen(RealmName),
-                                          RealmName,
-                                          ServiceName,
-                                          CellName,
-                                          0)) 
-        {
-            goto cleanup;
-        }
 
         increds.client = client_principal;
         increds.times.endtime = 0;
         /* Ask for DES since that is what V4 understands */
         increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
 
-
-        if ( IsDebuggerPresent() ) {
-            char * cname, *sname;
-            pkrb5_unparse_name(ctx, increds.client, &cname);
-            pkrb5_unparse_name(ctx, increds.server, &sname);
-            OutputDebugString("Getting tickets for \"");
-            OutputDebugString(cname);
-            OutputDebugString("\" and service \"");
-            OutputDebugString(sname);
-            OutputDebugString("\"\n");
-            pkrb5_free_unparsed_name(ctx,cname);
-            pkrb5_free_unparsed_name(ctx,sname);
-        }
-
-        code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
-        if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
-             code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
-             code == KRB5KRB_AP_ERR_MSG_TYPE) {
-            /* Or service@REALM */
-            pkrb5_free_principal(ctx,increds.server);
+        /* If there was a specific realm we are supposed to try
+         * then use it 
+         */
+        if (strlen(realm) != 0) {
+            /* service/cell@REALM */
             increds.server = 0;
             code = pkrb5_build_principal(ctx, &increds.server,
-                                          (int)strlen(RealmName),
-                                          RealmName,
-                                          ServiceName,
-                                          0);
-
+                                         (int)strlen(realm),
+                                         realm,
+                                         ServiceName,
+                                         CellName,
+                                         0);
             if ( IsDebuggerPresent() ) {
                 char * cname, *sname;
                 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 tickets for \"");
+                OutputDebugString("Getting tickets for \"");
                 OutputDebugString(cname);
                 OutputDebugString("\" and service \"");
                 OutputDebugString(sname);
@@ -2950,29 +2973,59 @@ KFW_AFS_klog(
 
             if (!code)
                 code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
-        }
 
-        if ((code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
-              code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
-              code == KRB5KRB_AP_ERR_MSG_TYPE) &&
-             strcmp(RealmName, realm_of_cell)) {
-            /* Or service/cell@REALM_OF_CELL */
-            strcpy(RealmName, realm_of_cell);
-            pkrb5_free_principal(ctx,increds.server);
-            increds.server = 0;
-            code = pkrb5_build_principal(ctx, &increds.server,
-                                         (int)strlen(RealmName),
-                                         RealmName,
-                                         ServiceName,
-                                         CellName,
-                                         0);
+            if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
+                code == KRB5_ERR_HOST_REALM_UNKNOWN ||
+                code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
+                code == KRB5KRB_AP_ERR_MSG_TYPE) {
+                /* Or service@REALM */
+                pkrb5_free_principal(ctx,increds.server);
+                increds.server = 0;
+                code = pkrb5_build_principal(ctx, &increds.server,
+                                              (int)strlen(realm),
+                                              realm,
+                                              ServiceName,
+                                              0);
+
+                if ( IsDebuggerPresent() ) {
+                    char * cname, *sname;
+                    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 tickets for \"");
+                    OutputDebugString(cname);
+                    OutputDebugString("\" and service \"");
+                    OutputDebugString(sname);
+                    OutputDebugString("\"\n");
+                    pkrb5_free_unparsed_name(ctx,cname);
+                    pkrb5_free_unparsed_name(ctx,sname);
+                }
+
+                if (!code)
+                    code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
+            }
+
+            if (code == 0) {
+                /* we have a local realm for the cell */
+                strcpy(realm_of_cell, realm);
+            }
+        } else {
+            /* Otherwise, first try service/cell@CLIENT_REALM */
+            if (code = pkrb5_build_principal(ctx, &increds.server,
+                                              (int)strlen(realm_of_user),
+                                              realm_of_user,
+                                              ServiceName,
+                                              CellName,
+                                              0)) 
+            {
+                goto cleanup;
+            }
 
             if ( IsDebuggerPresent() ) {
                 char * cname, *sname;
                 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 tickets for \"");
+                OutputDebugString("Getting tickets for \"");
                 OutputDebugString(cname);
                 OutputDebugString("\" and service \"");
                 OutputDebugString(sname);
@@ -2981,19 +3034,60 @@ KFW_AFS_klog(
                 pkrb5_free_unparsed_name(ctx,sname);
             }
 
-            if (!code)
-                code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
+            code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
+            if (code == 0) {
+                /* The client's realm is a local realm for the cell.
+                 * Save it so that later the pts registration will not
+                 * be performed.
+                 */
+                strcpy(realm_of_cell, realm_of_user);
+            }
 
-        
-            if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
+            if ((code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
+                 code == KRB5_ERR_HOST_REALM_UNKNOWN ||
                  code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
-                                code == KRB5KRB_AP_ERR_MSG_TYPE) {
-                /* Or service@REALM_OF_CELL */
+                 code == KRB5KRB_AP_ERR_MSG_TYPE) && 
+                 strcmp(realm_of_user, realm_of_cell)) {
+                /* Then service/cell@CELL_REALM */
                 pkrb5_free_principal(ctx,increds.server);
                 increds.server = 0;
                 code = pkrb5_build_principal(ctx, &increds.server,
-                                              (int)strlen(RealmName),
-                                              RealmName,
+                                              (int)strlen(realm_of_cell),
+                                              realm_of_cell,
+                                              ServiceName,
+                                              CellName,
+                                              0);
+                if ( IsDebuggerPresent() ) {
+                    char * cname, *sname;
+                    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 tickets for \"");
+                    OutputDebugString(cname);
+                    OutputDebugString("\" and service \"");
+                    OutputDebugString(sname);
+                    OutputDebugString("\"\n");
+                    pkrb5_free_unparsed_name(ctx,cname);
+                    pkrb5_free_unparsed_name(ctx,sname);
+                }
+
+                if (!code)
+                    code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
+
+                if (!code && !strlen(realm_of_cell)) 
+                    copy_realm_of_ticket(ctx, realm_of_cell, sizeof(realm_of_cell), k5creds);
+            }
+
+            if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
+                code == KRB5_ERR_HOST_REALM_UNKNOWN ||
+                code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
+                code == KRB5KRB_AP_ERR_MSG_TYPE) {
+                /* Finally service@CELL_REALM */
+                pkrb5_free_principal(ctx,increds.server);
+                increds.server = 0;
+                code = pkrb5_build_principal(ctx, &increds.server,
+                                              (int)strlen(realm_of_cell),
+                                              realm_of_cell,
                                               ServiceName,
                                               0);
 
@@ -3013,6 +3107,8 @@ KFW_AFS_klog(
 
                 if (!code)
                     code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
+                if (!code && !strlen(realm_of_cell)) 
+                    copy_realm_of_ticket(ctx, realm_of_cell, sizeof(realm_of_cell), k5creds);
             }
         }
 
@@ -3054,7 +3150,7 @@ KFW_AFS_klog(
                 retry++;
                 goto retry_gettoken5;
             }
-            goto try_krb524d;
+            goto cleanup;
         }
 
         if (atoken.kvno == btoken.kvno &&
@@ -3250,6 +3346,8 @@ KFW_AFS_klog(
         pkrb5_cc_close(ctx, cc);
     if (ctx && (ctx != alt_ctx))
         pkrb5_free_context(ctx);
+    if (ak_cellconfig.linkedCell)
+        free(ak_cellconfig.linkedCell);
 
     return(rc? rc : code);
 }
@@ -3296,7 +3394,8 @@ int
 KFW_AFS_get_cellconfig(char *cell, struct afsconf_cell *cellconfig, char *local_cell)
 {
     int        rc;
-    char newcell[MAXCELLCHARS+1];
+    char newcell[CELL_MAXNAMELEN+1];
+    char linkedcell[CELL_MAXNAMELEN+1]="";
 
     local_cell[0] = (char)0;
     memset(cellconfig, 0, sizeof(*cellconfig));
@@ -3311,15 +3410,19 @@ KFW_AFS_get_cellconfig(char *cell, struct afsconf_cell *cellconfig, char *local_
         strcpy(cell, local_cell);
 
     /* WIN32: cm_SearchCellFile(cell, pcallback, pdata) */
-    strcpy(cellconfig->name, cell);
-
-    rc = cm_SearchCellFile(cell, newcell, get_cellconfig_callback, (void*)cellconfig);
+    rc = cm_SearchCellFileEx(cell, newcell, linkedcell, get_cellconfig_callback, (void*)cellconfig);
 #ifdef AFS_AFSDB_ENV
     if (rc != 0) {
         int ttl;
         rc = cm_SearchCellByDNS(cell, newcell, &ttl, get_cellconfig_callback, (void*)cellconfig);
     }
 #endif
+
+    if (rc == 0) {
+        strcpy(cellconfig->name, newcell);
+        if (linkedcell[0])
+            cellconfig->linkedCell = strdup(linkedcell);
+    }
     return rc;
 }