* gc_frm_kdc.c (krb5_get_cred_from_kdc_opt): Free credentials retrieved from
authorKen Raeburn <raeburn@mit.edu>
Wed, 12 Jan 2005 01:06:04 +0000 (01:06 +0000)
committerKen Raeburn <raeburn@mit.edu>
Wed, 12 Jan 2005 01:06:04 +0000 (01:06 +0000)
ccache before returning.  Based on patch from fumihiko kakuma
<kakuma@valinux.co.jp>.  Also whitespace changes for readability.

ticket: 2541
tags: pullup
target_version: 1.4

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@17014 dc483132-0cff-0310-8789-dd5450dbe970

src/lib/krb5/krb/ChangeLog
src/lib/krb5/krb/gc_frm_kdc.c

index 4b01bfcb83b5a4a875a66e8b6acfa9cbacc2290a..c62d7dfee36a5094e784a7a68b89fd28697a9754 100644 (file)
@@ -1,3 +1,9 @@
+2005-01-11  Ken Raeburn  <raeburn@mit.edu>
+
+       * gc_frm_kdc.c (krb5_get_cred_from_kdc_opt): Free credentials
+       retrieved from ccache before returning.  Based on patch from
+       fumihiko kakuma <kakuma@valinux.co.jp>.
+
 2005-01-03  Ken Raeburn  <raeburn@mit.edu>
 
        * parse.c (krb5_parse_name): Don't cache the default realm name.
index 8ca62cce634ed8fcaf2cd038691adddd995a2c98..5aeca97fcde50c0a000ee1f04270b0dc1178b3da 100644 (file)
 #define FLAGS2OPTS(flags) (flags & KDC_TKT_COMMON_MASK)
 
 static krb5_error_code
-krb5_get_cred_from_kdc_opt(krb5_context context, krb5_ccache ccache, krb5_creds *in_cred, krb5_creds **out_cred, krb5_creds ***tgts, int kdcopt)
+krb5_get_cred_from_kdc_opt(krb5_context context, krb5_ccache ccache,
+                          krb5_creds *in_cred, krb5_creds **out_cred,
+                          krb5_creds ***tgts, int kdcopt)
 {
-  krb5_creds      **ret_tgts = NULL;
-  int             ntgts = 0;
+    krb5_creds      **ret_tgts = NULL;
+    int             ntgts = 0;
 
-  krb5_creds      tgt, tgtq, *tgtr = NULL;
-  krb5_error_code retval;
-  krb5_principal  int_server = NULL;    /* Intermediate server for request */
+    krb5_creds      tgt, tgtq, *tgtr = NULL, otgt;
+    krb5_error_code retval;
+    krb5_principal  int_server = NULL;    /* Intermediate server for request */
 
-  krb5_principal  *tgs_list = NULL;
-  krb5_principal  *top_server = NULL;
-  krb5_principal  *next_server = NULL;
-  unsigned int    nservers = 0;
-  krb5_boolean   old_use_conf_ktypes = context->use_conf_ktypes;
+    krb5_principal  *tgs_list = NULL;
+    krb5_principal  *top_server = NULL;
+    krb5_principal  *next_server = NULL;
+    unsigned int    nservers = 0;
+    krb5_boolean         old_use_conf_ktypes = context->use_conf_ktypes;
+    int                    retr_flags = KRB5_TC_MATCH_SRV_NAMEONLY | KRB5_TC_SUPPORTED_KTYPES;
+    int                    free_tgt = 0;
 
-  /* in case we never get a TGT, zero the return */
+    /* in case we never get a TGT, zero the return */
 
-  *tgts = NULL;
+    *tgts = NULL;
      
-  memset((char *)&tgtq, 0, sizeof(tgtq));
-  memset((char *)&tgt, 0, sizeof(tgt));
-
-  /*
-   * we know that the desired credentials aren't in the cache yet.
-   *
-   * To get them, we first need a tgt for the realm of the server.
-   * first, we see if we have such a TGT in cache.  if not, then
-   * we ask the kdc to give us one.  if that doesn't work, then
-   * we try to get a tgt for a realm that is closest to the target.
-   * once we have that, then we ask that realm if it can give us
-   * tgt for the target.  if not, we do the process over with this
-   * new tgt.
-   */
-  
-  /*
-   * (the ticket may be issued by some other intermediate
-   *  realm's KDC; so we use KRB5_TC_MATCH_SRV_NAMEONLY)
-   */
-  if ((retval = krb5_copy_principal(context, in_cred->client, &tgtq.client)))
-      goto cleanup;
-
-  /* get target tgt from cache */
-  if ((retval = krb5_tgtname(context, krb5_princ_realm(context, in_cred->server),
-                            krb5_princ_realm(context, in_cred->client),
-                            &int_server))) {
-      goto cleanup;
-  }
-
-  if ((retval = krb5_copy_principal(context, int_server, &tgtq.server))) {
-      goto cleanup;
-  }
-
-    context->use_conf_ktypes = 1;
-  if ((retval = krb5_cc_retrieve_cred(context, ccache,
-                                     KRB5_TC_MATCH_SRV_NAMEONLY | KRB5_TC_SUPPORTED_KTYPES,
-                                     &tgtq, &tgt))) {
-
-    if (retval != KRB5_CC_NOTFOUND && retval != KRB5_CC_NOT_KTYPE) {
-       goto cleanup;
-    }
+    memset((char *)&tgtq, 0, sizeof(tgtq));
+    memset((char *)&tgt, 0, sizeof(tgt));
+    memset((char *)&otgt, 0, sizeof(otgt));
 
     /*
-     * Note that we want to request a TGT from our local KDC, even
-     * if we already have a TGT for some intermediate realm.  The 
-     * reason is that our local KDC may have a shortcut to the
-     * destination realm, and if it does we want to use the
-     * shortcut because it will provide greater security. - bcn
+     * we know that the desired credentials aren't in the cache yet.
+     *
+     * To get them, we first need a tgt for the realm of the server.
+     * first, we see if we have such a TGT in cache.  if not, then
+     * we ask the kdc to give us one.  if that doesn't work, then
+     * we try to get a tgt for a realm that is closest to the target.
+     * once we have that, then we ask that realm if it can give us
+     * tgt for the target.  if not, we do the process over with this
+     * new tgt.
      */
   
     /*
-     * didn't find it in the cache so it is time to get a local
-     * tgt and walk the realms tree.
+     * (the ticket may be issued by some other intermediate
+     *  realm's KDC; so we use KRB5_TC_MATCH_SRV_NAMEONLY)
      */
-    krb5_free_principal(context, int_server);
-    int_server = NULL;
-    if ((retval = krb5_tgtname(context, 
-                              krb5_princ_realm(context, in_cred->client),
-                              krb5_princ_realm(context, in_cred->client),
-                              &int_server))) {
-       goto cleanup;
-    }
-  
-    krb5_free_cred_contents(context, &tgtq);
-    memset((char *)&tgtq, 0, sizeof(tgtq));
     if ((retval = krb5_copy_principal(context, in_cred->client, &tgtq.client)))
        goto cleanup;
-    if ((retval = krb5_copy_principal(context, int_server, &tgtq.server)))
-       goto cleanup;
 
-    if ((retval = krb5_cc_retrieve_cred(context, ccache,
-                                       KRB5_TC_MATCH_SRV_NAMEONLY | KRB5_TC_SUPPORTED_KTYPES,
-                                       &tgtq, &tgt))) {
+    /* get target tgt from cache */
+    if ((retval = krb5_tgtname(context,
+                              krb5_princ_realm(context, in_cred->server),
+                              krb5_princ_realm(context, in_cred->client),
+                              &int_server))) {
        goto cleanup;
     }
-  
-    /* get a list of realms to consult */
-  
-    if ((retval = krb5_walk_realm_tree(context, 
-                                      krb5_princ_realm(context,in_cred->client),
-                                      krb5_princ_realm(context,in_cred->server),
-                                      &tgs_list, 
-                                      KRB5_REALM_BRANCH_CHAR))) {
+
+    if ((retval = krb5_copy_principal(context, int_server, &tgtq.server))) {
        goto cleanup;
     }
-  
-    for (nservers = 0; tgs_list[nservers]; nservers++)
-      ;
-  
-    /* allocate storage for TGT pointers. */
-    
-    if (!(ret_tgts = (krb5_creds **) calloc(nservers+1, sizeof(krb5_creds)))) {
-      retval = ENOMEM;
-      goto cleanup;
-    }
-    *tgts = ret_tgts;
-    
-    /*
-     * step one is to take the current tgt and see if there is a tgt for
-     * krbtgt/realmof(target)@realmof(tgt).  if not, try to get one with
-     * the tgt.
-     *
-     * if we don't get a tgt for the target, then try to find a tgt as
-     * close to the target realm as possible. at each step if there isn't
-     * a tgt in the cache we have to try and get one with our latest tgt.
-     * once we have a tgt for a closer realm, we go back to step one.
-     *
-     * once we have a tgt for the target, we go try and get credentials.
-     */
-  
-    for (top_server = tgs_list;
-         top_server < tgs_list + nservers;
-         top_server = next_server) {
-    
-      /* look in cache for a tgt for the destination */
-    
-      krb5_free_cred_contents(context, &tgtq);
-      memset(&tgtq, 0, sizeof(tgtq));
-      if ((retval = krb5_copy_principal(context, tgt.client, &tgtq.client)))
-         goto cleanup;
-
-      krb5_free_principal(context, int_server);
-      int_server = NULL;
-      if ((retval = krb5_tgtname(context, 
-                                krb5_princ_realm(context, in_cred->server),
-                                krb5_princ_realm(context, *top_server),
-                                &int_server))) {
-         goto cleanup;
-      }
-    
-      if ((retval = krb5_copy_principal(context, int_server, &tgtq.server)))
-         goto cleanup;
 
-      if ((retval = krb5_cc_retrieve_cred(context, ccache,
-                                         KRB5_TC_MATCH_SRV_NAMEONLY | KRB5_TC_SUPPORTED_KTYPES,
-                                         &tgtq, &tgt))) {
-    
+    context->use_conf_ktypes = 1;
+    if ((retval = krb5_cc_retrieve_cred(context, ccache, retr_flags,
+                                       &tgtq, &tgt))) {
+
        if (retval != KRB5_CC_NOTFOUND && retval != KRB5_CC_NOT_KTYPE) {
            goto cleanup;
        }
+
+       /*
+        * Note that we want to request a TGT from our local KDC, even
+        * if we already have a TGT for some intermediate realm.  The 
+        * reason is that our local KDC may have a shortcut to the
+        * destination realm, and if it does we want to use the
+        * shortcut because it will provide greater security. - bcn
+        */
   
-       /* didn't find it in the cache so try and get one */
-       /* with current tgt.                              */
-    
-       if (!krb5_c_valid_enctype(tgt.keyblock.enctype)) {
-           retval = KRB5_PROG_ETYPE_NOSUPP;
+       /*
+        * didn't find it in the cache so it is time to get a local
+        * tgt and walk the realms tree.
+        */
+       krb5_free_principal(context, int_server);
+       int_server = NULL;
+       if ((retval = krb5_tgtname(context, 
+                                  krb5_princ_realm(context, in_cred->client),
+                                  krb5_princ_realm(context, in_cred->client),
+                                  &int_server))) {
            goto cleanup;
        }
-    
+  
        krb5_free_cred_contents(context, &tgtq);
-       memset(&tgtq, 0, sizeof(tgtq));
-       tgtq.times        = tgt.times;
-       if ((retval = krb5_copy_principal(context, tgt.client, &tgtq.client)))
+       memset((char *)&tgtq, 0, sizeof(tgtq));
+       if ((retval = krb5_copy_principal(context, in_cred->client,
+                                         &tgtq.client)))
            goto cleanup;
        if ((retval = krb5_copy_principal(context, int_server, &tgtq.server)))
            goto cleanup;
-       tgtq.is_skey      = FALSE;
-       tgtq.ticket_flags = tgt.ticket_flags;
-       retval = krb5_get_cred_via_tkt(context, &tgt,
-                                      FLAGS2OPTS(tgtq.ticket_flags),
-                                      tgt.addresses, &tgtq, &tgtr);
-       if (retval) {
-             
-       /*
-       * couldn't get one so now loop backwards through the realms
-       * list and try and get a tgt for a realm as close to the
-       * target as possible. the kdc should give us a tgt for the
-       * closest one it knows about, but not all kdc's do this yet.
-       */
+
+       if ((retval = krb5_cc_retrieve_cred(context, ccache,
+                                           retr_flags,
+                                           &tgtq, &tgt))) {
+           goto cleanup;
+       }
+       free_tgt = 1;
   
-         for (next_server = tgs_list + nservers - 1;
-              next_server > top_server;
-              next_server--) {
+       /* get a list of realms to consult */
+  
+       if ((retval = krb5_walk_realm_tree(context, 
+                                          krb5_princ_realm(context,
+                                                           in_cred->client),
+                                          krb5_princ_realm(context,
+                                                           in_cred->server),
+                                          &tgs_list, 
+                                          KRB5_REALM_BRANCH_CHAR))) {
+           goto cleanup;
+       }
+  
+       for (nservers = 0; tgs_list[nservers]; nservers++)
+           ;
+  
+       /* allocate storage for TGT pointers. */
+    
+       if (!(ret_tgts = (krb5_creds **) calloc(nservers+1,
+                                               sizeof(krb5_creds)))) {
+           retval = ENOMEM;
+           goto cleanup;
+       }
+       *tgts = ret_tgts;
+    
+       /*
+        * step one is to take the current tgt and see if there is a tgt for
+        * krbtgt/realmof(target)@realmof(tgt).  if not, try to get one with
+        * the tgt.
+        *
+        * if we don't get a tgt for the target, then try to find a tgt as
+        * close to the target realm as possible. at each step if there isn't
+        * a tgt in the cache we have to try and get one with our latest tgt.
+        * once we have a tgt for a closer realm, we go back to step one.
+        *
+        * once we have a tgt for the target, we go try and get credentials.
+        */
+  
+       for (top_server = tgs_list;
+            top_server < tgs_list + nservers;
+            top_server = next_server) {
+    
+           /* look in cache for a tgt for the destination */
+    
            krb5_free_cred_contents(context, &tgtq);
            memset(&tgtq, 0, sizeof(tgtq));
            if ((retval = krb5_copy_principal(context, tgt.client,
@@ -264,7 +217,8 @@ krb5_get_cred_from_kdc_opt(krb5_context context, krb5_ccache ccache, krb5_creds
            krb5_free_principal(context, int_server);
            int_server = NULL;
            if ((retval = krb5_tgtname(context, 
-                                      krb5_princ_realm(context, *next_server),
+                                      krb5_princ_realm(context,
+                                                       in_cred->server),
                                       krb5_princ_realm(context, *top_server),
                                       &int_server))) {
                goto cleanup;
@@ -274,151 +228,246 @@ krb5_get_cred_from_kdc_opt(krb5_context context, krb5_ccache ccache, krb5_creds
                                              &tgtq.server)))
                goto cleanup;
 
+           otgt = tgt;
            if ((retval = krb5_cc_retrieve_cred(context, ccache,
-                                               KRB5_TC_MATCH_SRV_NAMEONLY | KRB5_TC_SUPPORTED_KTYPES,
+                                               retr_flags,
                                                &tgtq, &tgt))) {
-             if (retval != KRB5_CC_NOTFOUND) {
-                 goto cleanup;
-             }
+    
+               if (retval != KRB5_CC_NOTFOUND && retval != KRB5_CC_NOT_KTYPE) {
+                   goto cleanup;
+               }
   
-             /* not in the cache so try and get one with our current tgt. */
+               /* didn't find it in the cache so try and get one */
+               /* with current tgt.                              */
+    
+               if (!krb5_c_valid_enctype(tgt.keyblock.enctype)) {
+                   retval = KRB5_PROG_ETYPE_NOSUPP;
+                   goto cleanup;
+               }
+    
+               krb5_free_cred_contents(context, &tgtq);
+               memset(&tgtq, 0, sizeof(tgtq));
+               tgtq.times        = tgt.times;
+               if ((retval = krb5_copy_principal(context, tgt.client,
+                                                 &tgtq.client)))
+                   goto cleanup;
+               if ((retval = krb5_copy_principal(context, int_server,
+                                                 &tgtq.server)))
+                   goto cleanup;
+               tgtq.is_skey      = FALSE;
+               tgtq.ticket_flags = tgt.ticket_flags;
+               retval = krb5_get_cred_via_tkt(context, &tgt,
+                                              FLAGS2OPTS(tgtq.ticket_flags),
+                                              tgt.addresses, &tgtq, &tgtr);
+               if (retval) {
+             
+                   /*
+                    * Couldn't get one so now loop backwards through
+                    * the realms list and try and get a tgt for a
+                    * realm as close to the target as possible.  The
+                    * kdc should give us a tgt for the closest one it
+                    * knows about, but not all kdc's do this yet.
+                    */
+  
+                   for (next_server = tgs_list + nservers - 1;
+                        next_server > top_server;
+                        next_server--) {
+                       krb5_free_cred_contents(context, &tgtq);
+                       memset(&tgtq, 0, sizeof(tgtq));
+                       if ((retval = krb5_copy_principal(context, tgt.client,
+                                                         &tgtq.client)))
+                           goto cleanup;
+
+                       krb5_free_principal(context, int_server);
+                       int_server = NULL;
+                       if ((retval = krb5_tgtname(context, 
+                                                  krb5_princ_realm(context, *next_server),
+                                                  krb5_princ_realm(context, *top_server),
+                                                  &int_server))) {
+                           goto cleanup;
+                       }
+    
+                       if ((retval = krb5_copy_principal(context, int_server,
+                                                         &tgtq.server)))
+                           goto cleanup;
+
+                       otgt = tgt;
+                       if ((retval = krb5_cc_retrieve_cred(context, ccache,
+                                                           retr_flags,
+                                                           &tgtq, &tgt))) {
+                           if (retval != KRB5_CC_NOTFOUND) {
+                               goto cleanup;
+                           }
   
-             if (!krb5_c_valid_enctype(tgt.keyblock.enctype)) {
-                 retval = KRB5_PROG_ETYPE_NOSUPP;
-                 goto cleanup;
-             }
+                           /* not in the cache so try and get one with our current tgt. */
+  
+                           if (!krb5_c_valid_enctype(tgt.keyblock.enctype)) {
+                               retval = KRB5_PROG_ETYPE_NOSUPP;
+                               goto cleanup;
+                           }
             
-             krb5_free_cred_contents(context, &tgtq);
-             memset(&tgtq, 0, sizeof(tgtq));
-             tgtq.times        = tgt.times;
-             if ((retval = krb5_copy_principal(context, tgt.client,
-                                               &tgtq.client)))
-                 goto cleanup;
-             if ((retval = krb5_copy_principal(context, int_server,
-                                               &tgtq.server)))
-                 goto cleanup;
-             tgtq.is_skey      = FALSE;
-             tgtq.ticket_flags = tgt.ticket_flags;
-             retval = krb5_get_cred_via_tkt(context, &tgt,
-                                            FLAGS2OPTS(tgtq.ticket_flags),
-                                            tgt.addresses,
-                                            &tgtq, &tgtr);
-             if (retval)
-                 continue;
+                           krb5_free_cred_contents(context, &tgtq);
+                           memset(&tgtq, 0, sizeof(tgtq));
+                           tgtq.times        = tgt.times;
+                           if ((retval = krb5_copy_principal(context,
+                                                             tgt.client,
+                                                             &tgtq.client)))
+                               goto cleanup;
+                           if ((retval = krb5_copy_principal(context,
+                                                             int_server,
+                                                             &tgtq.server)))
+                               goto cleanup;
+                           tgtq.is_skey      = FALSE;
+                           tgtq.ticket_flags = tgt.ticket_flags;
+                           retval = krb5_get_cred_via_tkt(context, &tgt,
+                                                          FLAGS2OPTS(tgtq.ticket_flags),
+                                                          tgt.addresses,
+                                                          &tgtq, &tgtr);
+                           if (retval)
+                               continue;
              
-             /* save tgt in return array */
-             if ((retval = krb5_copy_creds(context, tgtr,
-                                           &ret_tgts[ntgts]))) {
-                 goto cleanup;
-             }
-             krb5_free_creds(context, tgtr);
-             tgtr = NULL;
+                           /* save tgt in return array */
+                           if ((retval = krb5_copy_creds(context, tgtr,
+                                                         &ret_tgts[ntgts]))) {
+                               goto cleanup;
+                           }
+                           krb5_free_creds(context, tgtr);
+                           tgtr = NULL;
+
+                           if (free_tgt) {
+                               krb5_free_cred_contents(context, &tgt);
+                               free_tgt = 0;
+                           }
              
-             tgt = *ret_tgts[ntgts++];
-           }
+                           tgt = *ret_tgts[ntgts++];
+                       } else {
+                           if (free_tgt)
+                               krb5_free_cred_contents(context, &otgt);
+                           else
+                               free_tgt = 0;
+                       }
           
-           /* got one as close as possible, now start all over */
+                       /* got one as close as possible, now start all over */
   
-           break;
-         }
+                       break;
+                   }
   
-         if (next_server == top_server) {
-             goto cleanup;
-         }
-         continue;
-        }
+                   if (next_server == top_server) {
+                       goto cleanup;
+                   }
+                   continue;
+               }
  
-       /*
-        * Got a tgt.  If it is for the target realm we can go try for the
-        * credentials.  If it is not for the target realm, then make sure it
-        * is in the realms hierarchy and if so, save it and start the loop
-        * over from there.  Note that we only need to compare the instance
-        * names since that is the target realm of the tgt.
-        */
+               /*
+                * Got a tgt.  If it is for the target realm we can go
+                * try for the credentials.  If it is not for the
+                * target realm, then make sure it is in the realms
+                * hierarchy and if so, save it and start the loop
+                * over from there.  Note that we only need to compare
+                * the instance names since that is the target realm
+                * of the tgt.
+                */
     
-       for (next_server = top_server; *next_server; next_server++) {
-            krb5_data *realm_1 = krb5_princ_component(context, next_server[0], 1);
-            krb5_data *realm_2 = krb5_princ_component(context, tgtr->server, 1);
-           if (realm_1 != NULL &&
-               realm_2 != NULL &&
-                realm_1->length == realm_2->length &&
-                !memcmp(realm_1->data, realm_2->data, realm_1->length)) {
-               break;
-            }
-       }
-
-       if (!next_server) {
-           retval = KRB5_KDCREP_MODIFIED;
-           goto cleanup;
-       }
-
-       if ((retval = krb5_copy_creds(context, tgtr, &ret_tgts[ntgts]))) {
-           goto cleanup;
+               for (next_server = top_server; *next_server; next_server++) {
+                   krb5_data *realm_1 = krb5_princ_component(context,
+                                                             next_server[0],
+                                                             1);
+                   krb5_data *realm_2 = krb5_princ_component(context,
+                                                             tgtr->server, 1);
+                   if (realm_1 != NULL &&
+                       realm_2 != NULL &&
+                       realm_1->length == realm_2->length &&
+                       !memcmp(realm_1->data, realm_2->data, realm_1->length)) {
+                       break;
+                   }
+               }
+
+               if (!next_server) {
+                   retval = KRB5_KDCREP_MODIFIED;
+                   goto cleanup;
+               }
+
+               if ((retval = krb5_copy_creds(context, tgtr, &ret_tgts[ntgts]))) {
+                   goto cleanup;
+               }
+               krb5_free_creds(context, tgtr);
+               tgtr = NULL;
+
+               if (free_tgt) {
+                   krb5_free_cred_contents(context, &tgt);
+                   free_tgt = 0;
+               }
+
+               tgt = *ret_tgts[ntgts++];
+
+               /* we're done if it is the target */
+
+               if (!*next_server++) break;
+           } else {
+               if (free_tgt)
+                   krb5_free_cred_contents(context, &otgt);
+               else
+                   free_tgt = 1;
+           }
        }
-       krb5_free_creds(context, tgtr);
-       tgtr = NULL;
-    
-        tgt = *ret_tgts[ntgts++];
-
-        /* we're done if it is the target */
-
-        if (!*next_server++) break;
-      }
     }
-  }
 
-  /* got/finally have tgt!  try for the creds */
+    /* got/finally have tgt!  try for the creds */
 
-  if (!krb5_c_valid_enctype(tgt.keyblock.enctype)) {
-    retval = KRB5_PROG_ETYPE_NOSUPP;
-    goto cleanup;
-  }
+    if (!krb5_c_valid_enctype(tgt.keyblock.enctype)) {
+       retval = KRB5_PROG_ETYPE_NOSUPP;
+       goto cleanup;
+    }
 
-  context->use_conf_ktypes = old_use_conf_ktypes;
-  retval = krb5_get_cred_via_tkt(context, &tgt,
-                                FLAGS2OPTS(tgt.ticket_flags) |
-                                kdcopt |
-                                (in_cred->second_ticket.length ?
-                                 KDC_OPT_ENC_TKT_IN_SKEY : 0),
-                                tgt.addresses, in_cred, out_cred);
+    context->use_conf_ktypes = old_use_conf_ktypes;
+    retval = krb5_get_cred_via_tkt(context, &tgt,
+                                  FLAGS2OPTS(tgt.ticket_flags) |
+                                  kdcopt |
+                                  (in_cred->second_ticket.length ?
+                                   KDC_OPT_ENC_TKT_IN_SKEY : 0),
+                                  tgt.addresses, in_cred, out_cred);
 
-  /* cleanup and return */
+    /* cleanup and return */
 
 cleanup:
 
-  if (tgtr) krb5_free_creds(context, tgtr);
-  if(tgs_list)  krb5_free_realm_tree(context, tgs_list);
-  krb5_free_cred_contents(context, &tgtq); 
-  if (int_server) krb5_free_principal(context, int_server); 
-  if (ntgts == 0) {
-      *tgts = NULL;
-      if (ret_tgts)  free(ret_tgts);
-      krb5_free_cred_contents(context, &tgt);
-  }
-  context->use_conf_ktypes = old_use_conf_ktypes;
-  return(retval);
+    if (tgtr) krb5_free_creds(context, tgtr);
+    if(tgs_list)  krb5_free_realm_tree(context, tgs_list);
+    krb5_free_cred_contents(context, &tgtq); 
+    if (int_server) krb5_free_principal(context, int_server); 
+    if (ntgts == 0) {
+       *tgts = NULL;
+       if (ret_tgts)  free(ret_tgts);
+       free_tgt = 1;
+    } else if (free_tgt)
+       krb5_free_cred_contents(context, &otgt);
+    context->use_conf_ktypes = old_use_conf_ktypes;
+    return(retval);
 }
 
 krb5_error_code
-krb5_get_cred_from_kdc(krb5_context context, krb5_ccache ccache, krb5_creds *in_cred, krb5_creds **out_cred, krb5_creds ***tgts)
+krb5_get_cred_from_kdc(krb5_context context, krb5_ccache ccache,
+                      krb5_creds *in_cred, krb5_creds **out_cred,
+                      krb5_creds ***tgts)
 {
-
-  return krb5_get_cred_from_kdc_opt(context, ccache, in_cred, out_cred, tgts,
-                                   0);
+    return krb5_get_cred_from_kdc_opt(context, ccache, in_cred, out_cred, tgts,
+                                     0);
 }
 
 krb5_error_code
-krb5_get_cred_from_kdc_validate(krb5_context context, krb5_ccache ccache, krb5_creds *in_cred, krb5_creds **out_cred, krb5_creds ***tgts)
+krb5_get_cred_from_kdc_validate(krb5_context context, krb5_ccache ccache,
+                               krb5_creds *in_cred, krb5_creds **out_cred,
+                               krb5_creds ***tgts)
 {
-
-  return krb5_get_cred_from_kdc_opt(context, ccache, in_cred, out_cred, tgts,
-                                   KDC_OPT_VALIDATE);
+    return krb5_get_cred_from_kdc_opt(context, ccache, in_cred, out_cred, tgts,
+                                     KDC_OPT_VALIDATE);
 }
 
 krb5_error_code
-krb5_get_cred_from_kdc_renew(krb5_context context, krb5_ccache ccache, krb5_creds *in_cred, krb5_creds **out_cred, krb5_creds ***tgts)
+krb5_get_cred_from_kdc_renew(krb5_context context, krb5_ccache ccache,
+                            krb5_creds *in_cred, krb5_creds **out_cred,
+                            krb5_creds ***tgts)
 {
-
-  return krb5_get_cred_from_kdc_opt(context, ccache, in_cred, out_cred, tgts,
-                                   KDC_OPT_RENEW);
+    return krb5_get_cred_from_kdc_opt(context, ccache, in_cred, out_cred, tgts,
+                                     KDC_OPT_RENEW);
 }