Blame SOURCES/krb5-master-kinit-cccol.patch

5af5b2
commit d7b94742daae85329067b126d0a4bc5b2ea7e4a0
5af5b2
Author: Greg Hudson <ghudson@mit.edu>
5af5b2
Date:   Thu Sep 26 05:38:46 2013 -0400
5af5b2
5af5b2
    Improve kinit output credential cache selection
5af5b2
    
5af5b2
    If kinit chooses a client principal based on anything other than the
5af5b2
    current default ccache's principal name, apply collection rules if
5af5b2
    possible.  When applying collection rules, if we don't find an
5af5b2
    existing cache for the client principal, use the default cache if it
5af5b2
    is uninitialized, instead of creating a new one.
5af5b2
    
5af5b2
    ticket: 7689
5af5b2
5af5b2
diff --git a/src/clients/kinit/kinit.c b/src/clients/kinit/kinit.c
5af5b2
index 5ceede8..d9033ec 100644
5af5b2
--- a/src/clients/kinit/kinit.c
5af5b2
+++ b/src/clients/kinit/kinit.c
5af5b2
@@ -466,9 +466,12 @@ k5_begin(opts, k5)
5af5b2
     struct k5_data* k5;
5af5b2
 {
5af5b2
     krb5_error_code code = 0;
5af5b2
+    int success = 0;
5af5b2
     int flags = opts->enterprise ? KRB5_PRINCIPAL_PARSE_ENTERPRISE : 0;
5af5b2
-    krb5_ccache defcache;
5af5b2
-    const char *deftype;
5af5b2
+    krb5_ccache defcache = NULL;
5af5b2
+    krb5_principal defcache_princ = NULL, princ;
5af5b2
+    const char *deftype = NULL;
5af5b2
+    char *defrealm, *name;
5af5b2
 
5af5b2
     code = krb5_init_context(&k5->ctx);
5af5b2
     if (code) {
5af5b2
@@ -477,73 +480,153 @@ k5_begin(opts, k5)
5af5b2
     }
5af5b2
     errctx = k5->ctx;
5af5b2
 
5af5b2
-    /* Parse specified principal name now if we got one. */
5af5b2
-    if (opts->principal_name) {
5af5b2
-        if ((code = krb5_parse_name_flags(k5->ctx, opts->principal_name,
5af5b2
-                                          flags, &k5->me))) {
5af5b2
-            com_err(progname, code, _("when parsing name %s"),
5af5b2
-                    opts->principal_name);
5af5b2
-            return 0;
5af5b2
-        }
5af5b2
-    }
5af5b2
-
5af5b2
     if (opts->k5_out_cache_name) {
5af5b2
         code = krb5_cc_resolve(k5->ctx, opts->k5_out_cache_name, &k5->out_cc);
5af5b2
         if (code != 0) {
5af5b2
             com_err(progname, code, _("resolving ccache %s"),
5af5b2
                     opts->k5_out_cache_name);
5af5b2
-            return 0;
5af5b2
+            goto cleanup;
5af5b2
         }
5af5b2
         if (opts->verbose) {
5af5b2
             fprintf(stderr, _("Using specified cache: %s\n"),
5af5b2
                     opts->k5_out_cache_name);
5af5b2
         }
5af5b2
     } else {
5af5b2
-        if ((code = krb5_cc_default(k5->ctx, &defcache))) {
5af5b2
+        /* Resolve the default ccache and get its type and default principal
5af5b2
+         * (if it is initialized). */
5af5b2
+        code = krb5_cc_default(k5->ctx, &defcache);
5af5b2
+        if (code) {
5af5b2
             com_err(progname, code, _("while getting default ccache"));
5af5b2
-            return 0;
5af5b2
+            goto cleanup;
5af5b2
         }
5af5b2
         deftype = krb5_cc_get_type(k5->ctx, defcache);
5af5b2
-        if (k5->me != NULL && krb5_cc_support_switch(k5->ctx, deftype)) {
5af5b2
-            /* Use an existing cache for the specified principal if we can. */
5af5b2
-            code = krb5_cc_cache_match(k5->ctx, k5->me, &k5->out_cc);
5af5b2
-            if (code != 0 && code != KRB5_CC_NOTFOUND) {
5af5b2
-                com_err(progname, code, _("while searching for ccache for %s"),
5af5b2
-                        opts->principal_name);
5af5b2
-                krb5_cc_close(k5->ctx, defcache);
5af5b2
-                return 0;
5af5b2
+        if (krb5_cc_get_principal(k5->ctx, defcache, &defcache_princ) != 0)
5af5b2
+            defcache_princ = NULL;
5af5b2
+    }
5af5b2
+
5af5b2
+    /* Choose a client principal name. */
5af5b2
+    if (opts->principal_name != NULL) {
5af5b2
+        /* Use the specified principal name. */
5af5b2
+        code = krb5_parse_name_flags(k5->ctx, opts->principal_name, flags,
5af5b2
+                                     &k5->me);
5af5b2
+        if (code) {
5af5b2
+            com_err(progname, code, _("when parsing name %s"),
5af5b2
+                    opts->principal_name);
5af5b2
+            goto cleanup;
5af5b2
+        }
5af5b2
+    } else if (opts->anonymous) {
5af5b2
+        /* Use the anonymous principal for the local realm. */
5af5b2
+        code = krb5_get_default_realm(k5->ctx, &defrealm);
5af5b2
+        if (code) {
5af5b2
+            com_err(progname, code, _("while getting default realm"));
5af5b2
+            goto cleanup;
5af5b2
+        }
5af5b2
+        code = krb5_build_principal_ext(k5->ctx, &k5->me,
5af5b2
+                                        strlen(defrealm), defrealm,
5af5b2
+                                        strlen(KRB5_WELLKNOWN_NAMESTR),
5af5b2
+                                        KRB5_WELLKNOWN_NAMESTR,
5af5b2
+                                        strlen(KRB5_ANONYMOUS_PRINCSTR),
5af5b2
+                                        KRB5_ANONYMOUS_PRINCSTR,
5af5b2
+                                        0);
5af5b2
+        krb5_free_default_realm(k5->ctx, defrealm);
5af5b2
+        if (code) {
5af5b2
+            com_err(progname, code, _("while building principal"));
5af5b2
+            goto cleanup;
5af5b2
+        }
5af5b2
+    } else if (opts->action == INIT_KT) {
5af5b2
+        /* Use the default host/service name. */
5af5b2
+        code = krb5_sname_to_principal(k5->ctx, NULL, NULL, KRB5_NT_SRV_HST,
5af5b2
+                                       &k5->me);
5af5b2
+        if (code) {
5af5b2
+            com_err(progname, code,
5af5b2
+                    _("when creating default server principal name"));
5af5b2
+            goto cleanup;
5af5b2
+        }
5af5b2
+        if (k5->me->realm.data[0] == 0) {
5af5b2
+            code = krb5_unparse_name(k5->ctx, k5->me, &k5->name);
5af5b2
+            if (code == 0) {
5af5b2
+                com_err(progname, KRB5_ERR_HOST_REALM_UNKNOWN,
5af5b2
+                        _("(principal %s)"), k5->name);
5af5b2
+            } else {
5af5b2
+                com_err(progname, KRB5_ERR_HOST_REALM_UNKNOWN,
5af5b2
+                        _("for local services"));
5af5b2
             }
5af5b2
-            if (code == KRB5_CC_NOTFOUND) {
5af5b2
-                code = krb5_cc_new_unique(k5->ctx, deftype, NULL, &k5->out_cc);
5af5b2
-                if (code) {
5af5b2
-                    com_err(progname, code, _("while generating new ccache"));
5af5b2
-                    krb5_cc_close(k5->ctx, defcache);
5af5b2
-                    return 0;
5af5b2
-                }
5af5b2
-                if (opts->verbose) {
5af5b2
-                    fprintf(stderr, _("Using new cache: %s\n"),
5af5b2
-                            krb5_cc_get_name(k5->ctx, k5->out_cc));
5af5b2
-                }
5af5b2
-            } else if (opts->verbose) {
5af5b2
+            goto cleanup;
5af5b2
+        }
5af5b2
+    } else if (k5->out_cc != NULL) {
5af5b2
+        /* If the output ccache is initialized, use its principal. */
5af5b2
+        if (krb5_cc_get_principal(k5->ctx, k5->out_cc, &princ) == 0)
5af5b2
+            k5->me = princ;
5af5b2
+    } else if (defcache_princ != NULL) {
5af5b2
+        /* Use the default cache's principal, and use the default cache as the
5af5b2
+         * output cache. */
5af5b2
+        k5->out_cc = defcache;
5af5b2
+        defcache = NULL;
5af5b2
+        k5->me = defcache_princ;
5af5b2
+        defcache_princ = NULL;
5af5b2
+    }
5af5b2
+
5af5b2
+    /* If we still haven't chosen, use the local username. */
5af5b2
+    if (k5->me == NULL) {
5af5b2
+        name = get_name_from_os();
5af5b2
+        if (name == NULL) {
5af5b2
+            fprintf(stderr, _("Unable to identify user\n"));
5af5b2
+            goto cleanup;
5af5b2
+        }
5af5b2
+        code = krb5_parse_name_flags(k5->ctx, name, flags, &k5->me);
5af5b2
+        if (code) {
5af5b2
+            com_err(progname, code, _("when parsing name %s"),
5af5b2
+                    name);
5af5b2
+            goto cleanup;
5af5b2
+        }
5af5b2
+    }
5af5b2
+
5af5b2
+    if (k5->out_cc == NULL && krb5_cc_support_switch(k5->ctx, deftype)) {
5af5b2
+        /* Use an existing cache for the client principal if we can. */
5af5b2
+        code = krb5_cc_cache_match(k5->ctx, k5->me, &k5->out_cc);
5af5b2
+        if (code != 0 && code != KRB5_CC_NOTFOUND) {
5af5b2
+            com_err(progname, code, _("while searching for ccache for %s"),
5af5b2
+                    opts->principal_name);
5af5b2
+            goto cleanup;
5af5b2
+        }
5af5b2
+        if (code == 0) {
5af5b2
+            if (opts->verbose) {
5af5b2
                 fprintf(stderr, _("Using existing cache: %s\n"),
5af5b2
                         krb5_cc_get_name(k5->ctx, k5->out_cc));
5af5b2
             }
5af5b2
-            krb5_cc_close(k5->ctx, defcache);
5af5b2
             k5->switch_to_cache = 1;
5af5b2
-        } else {
5af5b2
-            k5->out_cc = defcache;
5af5b2
+        } else if (defcache_princ != NULL) {
5af5b2
+            /* Create a new cache to avoid overwriting the initialized default
5af5b2
+             * cache. */
5af5b2
+            code = krb5_cc_new_unique(k5->ctx, deftype, NULL, &k5->out_cc);
5af5b2
+            if (code) {
5af5b2
+                com_err(progname, code, _("while generating new ccache"));
5af5b2
+                goto cleanup;
5af5b2
+            }
5af5b2
             if (opts->verbose) {
5af5b2
-                fprintf(stderr, _("Using default cache: %s\n"),
5af5b2
+                fprintf(stderr, _("Using new cache: %s\n"),
5af5b2
                         krb5_cc_get_name(k5->ctx, k5->out_cc));
5af5b2
             }
5af5b2
+            k5->switch_to_cache = 1;
5af5b2
+        }
5af5b2
+    }
5af5b2
+
5af5b2
+    /* Use the default cache if we haven't picked one yet. */
5af5b2
+    if (k5->out_cc == NULL) {
5af5b2
+        k5->out_cc = defcache;
5af5b2
+        defcache = NULL;
5af5b2
+        if (opts->verbose) {
5af5b2
+            fprintf(stderr, _("Using default cache: %s\n"),
5af5b2
+                    krb5_cc_get_name(k5->ctx, k5->out_cc));
5af5b2
         }
5af5b2
     }
5af5b2
+
5af5b2
     if (opts->k5_in_cache_name) {
5af5b2
         code = krb5_cc_resolve(k5->ctx, opts->k5_in_cache_name, &k5->in_cc);
5af5b2
         if (code != 0) {
5af5b2
             com_err(progname, code, _("resolving ccache %s"),
5af5b2
                     opts->k5_in_cache_name);
5af5b2
-            return 0;
5af5b2
+            goto cleanup;
5af5b2
         }
5af5b2
         if (opts->verbose) {
5af5b2
             fprintf(stderr, _("Using specified input cache: %s\n"),
5af5b2
@@ -551,80 +634,24 @@ k5_begin(opts, k5)
5af5b2
         }
5af5b2
     }
5af5b2
 
5af5b2
-    if (!k5->me) {
5af5b2
-        /* No principal name specified */
5af5b2
-        if (opts->anonymous) {
5af5b2
-            char *defrealm;
5af5b2
-            code = krb5_get_default_realm(k5->ctx, &defrealm);
5af5b2
-            if (code) {
5af5b2
-                com_err(progname, code, _("while getting default realm"));
5af5b2
-                return 0;
5af5b2
-            }
5af5b2
-            code = krb5_build_principal_ext(k5->ctx, &k5->me,
5af5b2
-                                            strlen(defrealm), defrealm,
5af5b2
-                                            strlen(KRB5_WELLKNOWN_NAMESTR),
5af5b2
-                                            KRB5_WELLKNOWN_NAMESTR,
5af5b2
-                                            strlen(KRB5_ANONYMOUS_PRINCSTR),
5af5b2
-                                            KRB5_ANONYMOUS_PRINCSTR,
5af5b2
-                                            0);
5af5b2
-            krb5_free_default_realm(k5->ctx, defrealm);
5af5b2
-            if (code) {
5af5b2
-                com_err(progname, code, _("while building principal"));
5af5b2
-                return 0;
5af5b2
-            }
5af5b2
-        } else {
5af5b2
-            if (opts->action == INIT_KT) {
5af5b2
-                /* Use the default host/service name */
5af5b2
-                code = krb5_sname_to_principal(k5->ctx, NULL, NULL,
5af5b2
-                                               KRB5_NT_SRV_HST, &k5->me);
5af5b2
-                if (code) {
5af5b2
-                    com_err(progname, code,
5af5b2
-                            _("when creating default server principal name"));
5af5b2
-                    return 0;
5af5b2
-                }
5af5b2
-                if (k5->me->realm.data[0] == 0) {
5af5b2
-                    code = krb5_unparse_name(k5->ctx, k5->me, &k5->name);
5af5b2
-                    if (code == 0) {
5af5b2
-                        com_err(progname, KRB5_ERR_HOST_REALM_UNKNOWN,
5af5b2
-                                _("(principal %s)"), k5->name);
5af5b2
-                    } else {
5af5b2
-                        com_err(progname, KRB5_ERR_HOST_REALM_UNKNOWN,
5af5b2
-                                _("for local services"));
5af5b2
-                    }
5af5b2
-                    return 0;
5af5b2
-                }
5af5b2
-            } else {
5af5b2
-                /* Get default principal from cache if one exists */
5af5b2
-                code = krb5_cc_get_principal(k5->ctx, k5->out_cc,
5af5b2
-                                             &k5->me);
5af5b2
-                if (code) {
5af5b2
-                    char *name = get_name_from_os();
5af5b2
-                    if (!name) {
5af5b2
-                        fprintf(stderr, _("Unable to identify user\n"));
5af5b2
-                        return 0;
5af5b2
-                    }
5af5b2
-                    if ((code = krb5_parse_name_flags(k5->ctx, name,
5af5b2
-                                                      flags, &k5->me))) {
5af5b2
-                        com_err(progname, code, _("when parsing name %s"),
5af5b2
-                                name);
5af5b2
-                        return 0;
5af5b2
-                    }
5af5b2
-                }
5af5b2
-            }
5af5b2
-        }
5af5b2
-    }
5af5b2
 
5af5b2
     code = krb5_unparse_name(k5->ctx, k5->me, &k5->name);
5af5b2
     if (code) {
5af5b2
         com_err(progname, code, _("when unparsing name"));
5af5b2
-        return 0;
5af5b2
+        goto cleanup;
5af5b2
     }
5af5b2
     if (opts->verbose)
5af5b2
         fprintf(stderr, _("Using principal: %s\n"), k5->name);
5af5b2
 
5af5b2
     opts->principal_name = k5->name;
5af5b2
 
5af5b2
-    return 1;
5af5b2
+    success = 1;
5af5b2
+
5af5b2
+cleanup:
5af5b2
+    if (defcache != NULL)
5af5b2
+        krb5_cc_close(k5->ctx, defcache);
5af5b2
+    krb5_free_principal(k5->ctx, defcache_princ);
5af5b2
+    return success;
5af5b2
 }
5af5b2
 
5af5b2
 static void