windows-use-client-realm-for-tokens-20080329
authorJeffrey Altman <jaltman@secure-endpoints.com>
Sun, 30 Mar 2008 04:30:52 +0000 (04:30 +0000)
committerJeffrey Altman <jaltman@secure-endpoints.com>
Sun, 30 Mar 2008 04:30:52 +0000 (04:30 +0000)
LICENSE MIT

Two recent changes to the AFS/Kerberos landscape have been causing
problems for aklog and related modules.  First, the support for multiple
local realms for the cell has broken the pts auto-registration code
when the realm used for the token acquisition does not match the
realm belonging to the selected vldb server.  Second, Kerberos referrals
prevents detection of the realm of the vldb server.

This commit adds a new method of searching for the afs service principal.
The first attempt is for afs/<cell>@<CLIENT-REALM>.  If found, the
<CLIENT-REALM> is used as the realm of the cell.

The patch adds error handling for KRB5_ERR_HOST_REALM_UNKNOWN which is
returned when krb5_get_host_realm() can't determine the realm.

Duplicate queries are also avoided and copy_realm_of_ticket() is
properly employed.

src/WINNT/afsd/afskfw.c
src/WINNT/aklog/aklog.c
src/WINNT/netidmgr_plugin/afsfuncs.c

index da84abd..2e109c6 100644 (file)
@@ -2734,6 +2734,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, len, krb5_princ_realm(context, ticket->server)->data);
+        dest[len] = '\0';
+
+        pkrb5_free_ticket(context, ticket);
+    }
+}
+
 int
 KFW_AFS_klog(
     krb5_context alt_ctx,
@@ -2881,6 +2900,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 +2910,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 +2945,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 +3006,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(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(RealmName),
-                                              RealmName,
+                                              (int)strlen(realm_of_cell),
+                                              realm_of_cell,
                                               ServiceName,
                                               0);
 
@@ -3013,6 +3079,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);
             }
         }
 
index 2f290ed..bc15903 100644 (file)
@@ -14,7 +14,7 @@
  */
 
 /*
- * Copyright (c) 2007 Secure Endpoints Inc.
+ * Copyright (c) 2007-2008 Secure Endpoints Inc.
  *
  * All rights reserved.
  *
@@ -625,6 +625,25 @@ static int get_v5_user_realm(krb5_context context,char *realm)
     return(KSUCCESS);
 }
 
+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 = krb5_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, len, krb5_princ_realm(context, ticket->server)->data);
+        dest[len] = '\0';
+
+        krb5_free_ticket(context, ticket);
+    }
+}
+
 /*
 * Log to a cell.  If the cell has already been logged to, return without
 * doing anything.  Otherwise, log to it and mark that it has been logged
@@ -702,6 +721,12 @@ static int auth_to_cell(krb5_context context, char *cell, char *realm)
         int retry = 1;
        int realm_fallback = 0;
 
+        if ((status = get_v5_user_realm(context, realm_of_user)) != KSUCCESS) {
+            fprintf(stderr, "%s: Couldn't determine realm of user: %d\n",
+                     progname, status);
+            return(AKLOG_KERBEROS);
+        }
+
         if ( strchr(name,'.') != NULL ) {
             fprintf(stderr, "%s: Can't support principal names including a dot.\n",
                     progname);
@@ -709,51 +734,61 @@ static int auth_to_cell(krb5_context context, char *cell, char *realm)
         }
 
       try_v5:
-       if (realm && realm[0])
-           strcpy(realm_of_cell, realm);
-       else
-           strcpy(realm_of_cell,
-                   afs_realm_of_cell5(context, &ak_cellconfig, realm_fallback));
-
-       if (dflag)
-            printf("Getting v5 tickets: %s/%s@%s\n", name, instance, realm_of_cell);
-        status = get_v5cred(context, name, instance, realm_of_cell, 
+       if (realm && realm[0]) {
+            if (dflag)
+                printf("Getting v5 tickets: %s/%s@%s\n", name, instance, realm);
+            status = get_v5cred(context, name, instance, realm, 
 #ifdef HAVE_KRB4
                             use524 ? &c : NULL, 
 #else
                             NULL,
 #endif
                             &v5cred);
+            strcpy(realm_of_cell, realm);
+        } else {
+           strcpy(realm_of_cell,
+                   afs_realm_of_cell5(context, &ak_cellconfig, realm_fallback));
 
-        if (status == 0 && strcmp(realm_of_cell, "") == 0) {
-            krb5_error_code code;
-            krb5_ticket *ticket;
-
-            code = krb5_decode_ticket(&v5cred->ticket, &ticket);
-
-            if (code != 0) {
-                fprintf(stderr,
-                         "%s: Couldn't decode ticket to determine realm for "
-                         "cell %s.\n",
-                         progname, cell_to_use);
-            } else {
-                int len = krb5_princ_realm(context, ticket->server)->length;
-                /* This really shouldn't happen. */
-                if (len > REALM_SZ-1)
-                    len = REALM_SZ-1;
-
-                strncpy(realm_of_cell, krb5_princ_realm(context, ticket->server)->data, len);
-                realm_of_cell[len] = 0;
+            if (retry == 1 && realm_fallback == 0) {
+                /* Only try the realm_of_user once */
+                status = -1;
+                if (dflag)
+                    printf("Getting v5 tickets: %s/%s@%s\n", name, instance, realm_of_user);
+                status = get_v5cred(context, name, instance, realm_of_user, 
+#ifdef HAVE_KRB4
+                                     use524 ? &c : NULL, 
+#else
+                                     NULL,
+#endif
+                                     &v5cred);
+                if (status == 0) {
+                    /* we have determined that the client realm 
+                     * is a valid cell realm
+                     */
+                    strcpy(realm_of_cell, realm_of_user);
+                }
+            }
 
-                krb5_free_ticket(context, ticket);
+            if (status != 0 && (!retry || retry && strcmp(realm_of_user,realm_of_cell))) {
+                if (dflag)
+                    printf("Getting v5 tickets: %s/%s@%s\n", name, instance, realm_of_cell);
+                status = get_v5cred(context, name, instance, realm_of_cell, 
+#ifdef HAVE_KRB4
+                                     use524 ? &c : NULL, 
+#else
+                                     NULL,
+#endif
+                                     &v5cred);
+                if (!status && !strlen(realm_of_cell)) 
+                    copy_realm_of_ticket(context, realm_of_cell, sizeof(realm_of_cell), v5cred);
             }
         }
 
-       if (status == KRB5_ERR_HOST_REALM_UNKNOWN) {
+       if (!realm_fallback && status == KRB5_ERR_HOST_REALM_UNKNOWN) {
            realm_fallback = 1;
            goto try_v5;
        } else if (status == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN) {
-           if (!realm_of_cell[0]) {
+           if (!realm_fallback && !realm_of_cell[0]) {
                realm_fallback = 1;
                goto try_v5;
            }
@@ -766,7 +801,10 @@ static int auth_to_cell(krb5_context context, char *cell, char *realm)
                                 NULL,
 #endif
                                 &v5cred);
+            if (!status && !strlen(realm_of_cell)) 
+                copy_realm_of_ticket(context, realm_of_cell, sizeof(realm_of_cell), v5cred);
        }
+     
         if ( status == KRB5KRB_AP_ERR_MSG_TYPE && retry ) {
             retry = 0;
            realm_fallback = 0;
@@ -890,13 +928,7 @@ static int auth_to_cell(krb5_context context, char *cell, char *realm)
     }       
     else    
     {
-        if (usev5) {
-            if((status = get_v5_user_realm(context, realm_of_user)) != KSUCCESS) {
-                fprintf(stderr, "%s: Couldn't determine realm of user: %d\n",
-                         progname, status);
-                return(AKLOG_KERBEROS);
-            }
-        } else {
+        if (!usev5) {
 #ifdef HAVE_KRB4
             if ((status = krb_get_tf_realm(TKT_FILE, realm_of_user)) != KSUCCESS)
             {
@@ -909,12 +941,9 @@ static int auth_to_cell(krb5_context context, char *cell, char *realm)
 #endif
         }
 
-        /* For Khimaira we want to always append the realm to the name */
-        if (1 /* strcmp(realm_of_user, realm_of_cell) */)
-        {
-            strcat(username, "@");
-            strcat(username, realm_of_user);
-        }
+        /* For Network Identity Manager append the realm to the name */
+        strcat(username, "@");
+        strcat(username, realm_of_user);
 
         ViceIDToUsername(username, realm_of_user, realm_of_cell, cell_to_use, 
 #ifdef HAVE_KRB4
index 66eab2a..15abc69 100644 (file)
@@ -841,17 +841,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 +850,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);