s4:auth/kerberos: protect kerberos_kinit_password_cc() against old KDCs
authorStefan Metzmacher <metze@samba.org>
Tue, 21 Jun 2011 09:05:15 +0000 (11:05 +0200)
committerStefan Metzmacher <metze@samba.org>
Wed, 22 Jun 2011 15:05:14 +0000 (17:05 +0200)
If the KDC does not support S4U2Proxy, it might return a ticket
for the TGT client principal.

metze

source4/auth/kerberos/kerberos.c

index d32559ed81e228edefd3eac5534b5f63625f4df5..0fc9d143abdbe00a92ad4568cbab635f25c0d7fc 100644 (file)
        krb5_ccache tmp_cc;
        const char *self_realm;
        krb5_principal blacklist_principal = NULL;
+       krb5_principal whitelist_principal = NULL;
 
        if (impersonate_principal && self_service == NULL) {
                return EINVAL;
                             s4u2self_creds->ticket.length,
                             &s4u2self_ticket,
                             &s4u2self_ticketlen);
-       krb5_free_creds(ctx, s4u2self_creds);
        if (code != 0) {
+               krb5_free_creds(ctx, s4u2self_creds);
                krb5_free_principal(ctx, blacklist_principal);
                krb5_cc_destroy(ctx, tmp_cc);
                return code;
        }
 
+       /*
+        * we need to remember the client principal of the
+        * S4U2Self stage and as it needs to match the one we
+        * will get for the S4U2Proxy stage. We need this
+        * in order to detect KDCs which does not support S4U2Proxy.
+        */
+       whitelist_principal = s4u2self_creds->client;
+       s4u2self_creds->client = NULL;
+       krb5_free_creds(ctx, s4u2self_creds);
+
        /*
         * For S4U2Proxy we also got a target service principal,
         * which also belongs to our own realm (available on
        code = krb5_parse_name(ctx, target_service, &target_princ);
        if (code != 0) {
                free_Ticket(&s4u2self_ticket);
+               krb5_free_principal(ctx, whitelist_principal);
                krb5_free_principal(ctx, blacklist_principal);
                krb5_cc_destroy(ctx, tmp_cc);
                return code;
        if (code != 0) {
                free_Ticket(&s4u2self_ticket);
                krb5_free_principal(ctx, target_princ);
+               krb5_free_principal(ctx, whitelist_principal);
                krb5_free_principal(ctx, blacklist_principal);
                krb5_cc_destroy(ctx, tmp_cc);
                return code;
        if (code != 0) {
                free_Ticket(&s4u2self_ticket);
                krb5_free_principal(ctx, target_princ);
+               krb5_free_principal(ctx, whitelist_principal);
                krb5_free_principal(ctx, blacklist_principal);
                krb5_cc_destroy(ctx, tmp_cc);
                return code;
        if (code != 0) {
                krb5_get_creds_opt_free(ctx, options);
                krb5_free_principal(ctx, target_princ);
+               krb5_free_principal(ctx, whitelist_principal);
                krb5_free_principal(ctx, blacklist_principal);
                krb5_cc_destroy(ctx, tmp_cc);
                return code;
        krb5_free_principal(ctx, target_princ);
        krb5_cc_destroy(ctx, tmp_cc);
        if (code != 0) {
+               krb5_free_principal(ctx, whitelist_principal);
                krb5_free_principal(ctx, blacklist_principal);
                return code;
        }
                                        &store_creds);
        krb5_free_creds(ctx, s4u2proxy_creds);
        if (code != 0) {
+               krb5_free_principal(ctx, whitelist_principal);
                krb5_free_principal(ctx, blacklist_principal);
                return code;
        }
                SAFE_FREE(sp);
                SAFE_FREE(ip);
 
+               krb5_free_principal(ctx, whitelist_principal);
                krb5_free_principal(ctx, blacklist_principal);
                krb5_free_cred_contents(ctx, &store_creds);
                return KRB5_FWD_BAD_PRINCIPAL;
                krb5_free_principal(ctx, blacklist_principal);
        }
 
+       if (whitelist_principal &&
+           !krb5_principal_compare(ctx, store_creds.client, whitelist_principal)) {
+               char *sp = NULL;
+               char *ep = NULL;
+
+               code = krb5_unparse_name(ctx, store_creds.client, &sp);
+               if (code != 0) {
+                       sp = NULL;
+               }
+               code = krb5_unparse_name(ctx, whitelist_principal, &ep);
+               if (code != 0) {
+                       ep = NULL;
+               }
+               DEBUG(1, ("kerberos_kinit_password_cc: "
+                         "KDC returned wrong principal[%s] we expected [%s]\n",
+                         sp?sp:"<no memory>",
+                         ep?ep:"<no memory>"));
+
+               SAFE_FREE(sp);
+               SAFE_FREE(ep);
+
+               krb5_free_principal(ctx, whitelist_principal);
+               krb5_free_cred_contents(ctx, &store_creds);
+               return KRB5_FWD_BAD_PRINCIPAL;
+       }
+       if (whitelist_principal) {
+               krb5_free_principal(ctx, whitelist_principal);
+       }
+
        code = krb5_cc_initialize(ctx, store_cc, store_principal);
        if (code != 0) {
                krb5_free_cred_contents(ctx, &store_creds);