[SCM] Samba Shared Repository - branch master updated

Stefan Metzmacher metze at samba.org
Wed Jun 22 01:11:02 MDT 2011


The branch, master has been updated
       via  ede3046 s4:auth/kerberos: protect kerberos_kinit_password_cc() against old KDCs
       via  e5378e6 s4:auth/kerberos: remove one indentation level in kerberos_kinit_password_cc()
       via  b98428e s4:auth/kerberos: reformat kerberos_kinit_password_cc()
       via  9c56303 s4:auth/kerberos: don't mix s4u2self creds with machine account creds
       via  b3d4962 s4:auth/kerberos: use better variable names in kerberos_kinit_password_cc()
       via  7cf3842 s4:auth/kerberos: don't ignore return code in kerberos_kinit_password_cc()
      from  9e766f0 samba-tool: added missing GUID component checks to dbcheck

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit ede3046b8b9b0576a35626026cb28c31b42da46d
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Jun 21 01:39:58 2011 +0200

    s4:auth/kerberos: protect kerberos_kinit_password_cc() against old KDCs
    
    Old KDCs may not support S4U2Self (or S4U2Proxy) and return tickets
    which belongs to the client principal of the TGT.
    
    metze
    
    Autobuild-User: Stefan Metzmacher <metze at samba.org>
    Autobuild-Date: Wed Jun 22 09:10:55 CEST 2011 on sn-devel-104

commit e5378e600e507241dd64c1ea7345676076dc8755
Author: Stefan Metzmacher <metze at samba.org>
Date:   Mon Jun 20 21:23:45 2011 +0200

    s4:auth/kerberos: remove one indentation level in kerberos_kinit_password_cc()
    
    This will make the following changes easier to review.
    
    metze

commit b98428e630cc5a1bbc18bf4260030a24322fdf9e
Author: Stefan Metzmacher <metze at samba.org>
Date:   Mon Jun 20 21:09:13 2011 +0200

    s4:auth/kerberos: reformat kerberos_kinit_password_cc()
    
    In order to make the following changes easier to review.
    
    metze

commit 9c56303f5a56697470ea9f2ee1a428aed2367d75
Author: Stefan Metzmacher <metze at samba.org>
Date:   Mon Jun 20 15:27:58 2011 +0200

    s4:auth/kerberos: don't mix s4u2self creds with machine account creds
    
    It's important that we don't store the tgt for the machine account
    in the same krb5_ccache as the ticket for the impersonated principal.
    
    We may pass it to some krb5/gssapi functions and they may use them
    in the wrong way, which would grant machine account privileges to
    the client.
    
    metze

commit b3d49620875d878e2ad39896a6fe9fddb039253e
Author: Stefan Metzmacher <metze at samba.org>
Date:   Mon Jun 20 18:01:49 2011 +0200

    s4:auth/kerberos: use better variable names in kerberos_kinit_password_cc()
    
    This will make the following changes easier to review.
    
    metze

commit 7cf38425b274c43144a2216accf5330d8ef1fe36
Author: Stefan Metzmacher <metze at samba.org>
Date:   Mon Jun 20 17:41:52 2011 +0200

    s4:auth/kerberos: don't ignore return code in kerberos_kinit_password_cc()
    
    metze

-----------------------------------------------------------------------

Summary of changes:
 source4/auth/kerberos/kerberos.c |  228 +++++++++++++++++++++++++++++--------
 1 files changed, 178 insertions(+), 50 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source4/auth/kerberos/kerberos.c b/source4/auth/kerberos/kerberos.c
index 0db0dd3..fa8c64b 100644
--- a/source4/auth/kerberos/kerberos.c
+++ b/source4/auth/kerberos/kerberos.c
@@ -84,82 +84,210 @@
   The target_service defaults to the krbtgt if NULL, but could be kpasswd/realm or the local service (if we are doing s4u2self)
 
 */
- krb5_error_code kerberos_kinit_password_cc(krb5_context ctx, krb5_ccache cc, 
-					    krb5_principal principal, const char *password,
-					    krb5_principal impersonate_principal, const char *target_service,
+ krb5_error_code kerberos_kinit_password_cc(krb5_context ctx, krb5_ccache store_cc,
+					    krb5_principal init_principal,
+					    const char *init_password,
+					    krb5_principal impersonate_principal,
+					    const char *target_service,
 					    krb5_get_init_creds_opt *krb_options,
 					    time_t *expire_time, time_t *kdc_time)
 {
 	krb5_error_code code = 0;
-	krb5_creds my_creds;
-	krb5_creds *impersonate_creds;
 	krb5_get_creds_opt options;
+	krb5_principal store_principal;
+	krb5_creds store_creds;
+	const char *self_service = target_service;
+	krb5_creds *s4u2self_creds;
+	krb5_principal self_princ;
+	krb5_ccache tmp_cc;
+	const char *self_realm;
+	krb5_principal blacklist_principal = NULL;
 
-	/* If we are not impersonating, then get this ticket for the
+	/*
+	 * If we are not impersonating, then get this ticket for the
 	 * target service, otherwise a krbtgt, and get the next ticket
-	 * for the target */
-	if ((code = krb5_get_init_creds_password(ctx, &my_creds, principal, password, 
-						 NULL, NULL,
-						 0,
-						 impersonate_principal ? NULL : target_service,
-						 krb_options))) {
+	 * for the target
+	 */
+	code = krb5_get_init_creds_password(ctx, &store_creds,
+					    init_principal,
+					    init_password,
+					    NULL, NULL,
+					    0,
+					    impersonate_principal ? NULL : target_service,
+					    krb_options);
+	if (code != 0) {
 		return code;
 	}
 
-	if ((code = krb5_cc_initialize(ctx, cc, principal))) {
-		krb5_free_cred_contents(ctx, &my_creds);
+	store_principal = init_principal;
+
+	if (impersonate_principal == NULL) {
+		goto store;
+	}
+
+	/*
+	 * We are trying S4U2Self now:
+	 *
+	 * As we do not want to expose our TGT in the
+	 * krb5_ccache, which is also holds the impersonated creds.
+	 *
+	 * Some low level krb5/gssapi function might use the TGT
+	 * identity and let the client act as our machine account.
+	 *
+	 * We need to avoid that and use a temporary krb5_ccache
+	 * in order to pass our TGT to the krb5_get_creds() function.
+	 */
+	code = krb5_cc_new_unique(ctx, NULL, NULL, &tmp_cc);
+	if (code != 0) {
+		krb5_free_cred_contents(ctx, &store_creds);
 		return code;
 	}
-	
-	if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
-		krb5_free_cred_contents(ctx, &my_creds);
+
+	code = krb5_cc_initialize(ctx, tmp_cc, store_creds.client);
+	if (code != 0) {
+		krb5_cc_destroy(ctx, tmp_cc);
+		krb5_free_cred_contents(ctx, &store_creds);
 		return code;
 	}
-	
-	if (expire_time) {
-		*expire_time = (time_t) my_creds.times.endtime;
+
+	code = krb5_cc_store_cred(ctx, tmp_cc, &store_creds);
+	if (code != 0) {
+		krb5_free_cred_contents(ctx, &store_creds);
+		krb5_cc_destroy(ctx, tmp_cc);
+		return code;
 	}
 
-	if (kdc_time) {
-		*kdc_time = (time_t) my_creds.times.starttime;
+	/*
+	 * we need to remember the client principal of our
+	 * TGT and make sure the KDC does not return this
+	 * in the impersonated tickets. This can happen
+	 * if the KDC does not support S4U2Self and S4U2Proxy.
+	 */
+	blacklist_principal = store_creds.client;
+	store_creds.client = NULL;
+	krb5_free_cred_contents(ctx, &store_creds);
+
+	/*
+	 * For S4U2Self we need our own service principal,
+	 * which belongs to our own realm (available on
+	 * our client principal).
+	 */
+	self_realm = krb5_principal_get_realm(ctx, init_principal);
+
+	code = krb5_parse_name(ctx, self_service, &self_princ);
+	if (code != 0) {
+		krb5_free_principal(ctx, blacklist_principal);
+		krb5_cc_destroy(ctx, tmp_cc);
+		return code;
 	}
 
-	krb5_free_cred_contents(ctx, &my_creds);
-	
-	if (code == 0 && impersonate_principal) {
-		krb5_principal target_princ;
-		if ((code = krb5_get_creds_opt_alloc(ctx, &options))) {
-			return code;
-		}
+	code = krb5_principal_set_realm(ctx, self_princ, self_realm);
+	if (code != 0) {
+		krb5_free_principal(ctx, blacklist_principal);
+		krb5_free_principal(ctx, self_princ);
+		krb5_cc_destroy(ctx, tmp_cc);
+		return code;
+	}
 
-		if ((code = krb5_get_creds_opt_set_impersonate(ctx, options, impersonate_principal))) {
-			krb5_get_creds_opt_free(ctx, options);
-			return code;
-		}
+	code = krb5_get_creds_opt_alloc(ctx, &options);
+	if (code != 0) {
+		krb5_free_principal(ctx, blacklist_principal);
+		krb5_free_principal(ctx, self_princ);
+		krb5_cc_destroy(ctx, tmp_cc);
+		return code;
+	}
 
-		if ((code = krb5_parse_name(ctx, target_service, &target_princ))) {
-			krb5_get_creds_opt_free(ctx, options);
-			return code;
-		}
+	code = krb5_get_creds_opt_set_impersonate(ctx, options,
+						  impersonate_principal);
+	if (code != 0) {
+		krb5_get_creds_opt_free(ctx, options);
+		krb5_free_principal(ctx, blacklist_principal);
+		krb5_free_principal(ctx, self_princ);
+		krb5_cc_destroy(ctx, tmp_cc);
+		return code;
+	}
 
-		if ((code = krb5_principal_set_realm(ctx, target_princ, krb5_principal_get_realm(ctx, principal)))) {
-			krb5_get_creds_opt_free(ctx, options);
-			krb5_free_principal(ctx, target_princ);
-			return code;
-		}
+	code = krb5_get_creds(ctx, options, tmp_cc,
+			      self_princ, &s4u2self_creds);
+	krb5_get_creds_opt_free(ctx, options);
+	krb5_free_principal(ctx, self_princ);
+	krb5_cc_destroy(ctx, tmp_cc);
+	if (code != 0) {
+		krb5_free_principal(ctx, blacklist_principal);
+		return code;
+	}
 
-		if ((code = krb5_get_creds(ctx, options, cc, target_princ, &impersonate_creds))) {
-			krb5_free_principal(ctx, target_princ);
-			krb5_get_creds_opt_free(ctx, options);
-			return code;
+	/*
+	 * Now make sure we store the impersonated principal
+	 * and creds instead of the TGT related stuff
+	 * in the krb5_ccache of the caller.
+	 */
+	code = krb5_copy_creds_contents(ctx, s4u2self_creds,
+					&store_creds);
+	krb5_free_creds(ctx, s4u2self_creds);
+	if (code != 0) {
+		krb5_free_principal(ctx, blacklist_principal);
+		return code;
+	}
+
+	/*
+	 * It's important to store the principal the KDC
+	 * returned, as otherwise the caller would not find
+	 * the S4U2Self ticket in the krb5_ccache lookup.
+	 */
+	store_principal = store_creds.client;
+
+ store:
+	if (blacklist_principal &&
+	    krb5_principal_compare(ctx, store_creds.client, blacklist_principal)) {
+		char *sp = NULL;
+		char *ip = NULL;
+
+		code = krb5_unparse_name(ctx, blacklist_principal, &sp);
+		if (code != 0) {
+			sp = NULL;
+		}
+		code = krb5_unparse_name(ctx, impersonate_principal, &ip);
+		if (code != 0) {
+			ip = NULL;
 		}
+		DEBUG(1, ("kerberos_kinit_password_cc: "
+			  "KDC returned self principal[%s] while impersonating [%s]\n",
+			  sp?sp:"<no memory>",
+			  ip?ip:"<no memory>"));
 
-		krb5_free_principal(ctx, target_princ);
+		SAFE_FREE(sp);
+		SAFE_FREE(ip);
 
-		code = krb5_cc_store_cred(ctx, cc, impersonate_creds);
-		krb5_get_creds_opt_free(ctx, options);
-		krb5_free_creds(ctx, impersonate_creds);
+		krb5_free_principal(ctx, blacklist_principal);
+		krb5_free_cred_contents(ctx, &store_creds);
+		return KRB5_FWD_BAD_PRINCIPAL;
 	}
+	if (blacklist_principal) {
+		krb5_free_principal(ctx, blacklist_principal);
+	}
+
+	code = krb5_cc_initialize(ctx, store_cc, store_principal);
+	if (code != 0) {
+		krb5_free_cred_contents(ctx, &store_creds);
+		return code;
+	}
+
+	code = krb5_cc_store_cred(ctx, store_cc, &store_creds);
+	if (code != 0) {
+		krb5_free_cred_contents(ctx, &store_creds);
+		return code;
+	}
+
+	if (expire_time) {
+		*expire_time = (time_t) store_creds.times.endtime;
+	}
+
+	if (kdc_time) {
+		*kdc_time = (time_t) store_creds.times.starttime;
+	}
+
+	krb5_free_cred_contents(ctx, &store_creds);
 
 	return 0;
 }


-- 
Samba Shared Repository


More information about the samba-cvs mailing list