[SCM] Samba Shared Repository - branch master updated

Stefan Metzmacher metze at samba.org
Wed Jun 22 10:18:02 MDT 2011


The branch, master has been updated
       via  5a8ac84 s4:ntvfs/cifs: add option to use S4U2Proxy
       via  033f337 s4:auth/kerberos: protect kerberos_kinit_password_cc() against old KDCs
       via  b9e095f s4:auth/kerberos: add S4U2Proxy support to kerberos_kinit_password_cc()
      from  d4c30a5 Update eDirectory schema

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


- Log -----------------------------------------------------------------
commit 5a8ac842701b65c0abd9731545792c2a0fd2aa79
Author: Stefan Metzmacher <metze at samba.org>
Date:   Fri Mar 11 08:32:22 2011 +0100

    s4:ntvfs/cifs: add option to use S4U2Proxy
    
    Note: this doesn't work against a Samba4 KDC yet.
    
    metze
    
    Autobuild-User: Stefan Metzmacher <metze at samba.org>
    Autobuild-Date: Wed Jun 22 18:17:43 CEST 2011 on sn-devel-104

commit 033f3376a834c1078b377647069b7e30aef59667
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Jun 21 11:05:15 2011 +0200

    s4:auth/kerberos: protect kerberos_kinit_password_cc() against old KDCs
    
    If the KDC does not support S4U2Proxy, it might return a ticket
    for the TGT client principal.
    
    metze

commit b9e095fdfb684005f9bb5c1d943b2a0705308500
Author: Stefan Metzmacher <metze at samba.org>
Date:   Mon Jun 20 20:28:44 2011 +0200

    s4:auth/kerberos: add S4U2Proxy support to kerberos_kinit_password_cc()
    
    For S4U2Proxy we need to use the ticket from the S4U2Self stage
    and ask the kdc for the delegated ticket for the target service.
    
    metze

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

Summary of changes:
 source4/auth/kerberos/kerberos.c      |  181 ++++++++++++++++++++++++++++++++-
 source4/auth/kerberos/kerberos.h      |    4 +-
 source4/auth/kerberos/kerberos_util.c |    1 +
 source4/ntvfs/cifs/vfs_cifs.c         |   49 +++++++++
 4 files changed, 230 insertions(+), 5 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source4/auth/kerberos/kerberos.c b/source4/auth/kerberos/kerberos.c
index fa8c64b..0fc9d14 100644
--- a/source4/auth/kerberos/kerberos.c
+++ b/source4/auth/kerberos/kerberos.c
@@ -81,13 +81,16 @@
 
   The impersonate_principal is the principal if NULL, or the principal to impersonate
 
-  The target_service defaults to the krbtgt if NULL, but could be kpasswd/realm or the local service (if we are doing s4u2self)
+  The self_service, should be the local service (for S4U2Self if impersonate_principal is given).
+
+  The target_service defaults to the krbtgt if NULL, but could be kpasswd/realm or a remote service (for S4U2Proxy)
 
 */
  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 *self_service,
 					    const char *target_service,
 					    krb5_get_init_creds_opt *krb_options,
 					    time_t *expire_time, time_t *kdc_time)
@@ -96,12 +99,21 @@
 	krb5_get_creds_opt options;
 	krb5_principal store_principal;
 	krb5_creds store_creds;
-	const char *self_service = target_service;
 	krb5_creds *s4u2self_creds;
+	Ticket s4u2self_ticket;
+	size_t s4u2self_ticketlen;
+	krb5_creds *s4u2proxy_creds;
 	krb5_principal self_princ;
+	bool s4u2proxy;
+	krb5_principal target_princ;
 	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;
+	}
 
 	/*
 	 * If we are not impersonating, then get this ticket for the
@@ -168,6 +180,18 @@
 	krb5_free_cred_contents(ctx, &store_creds);
 
 	/*
+	 * Check if we also need S4U2Proxy or if S4U2Self is
+	 * enough in order to get a ticket for the target.
+	 */
+	if (target_service == NULL) {
+		s4u2proxy = false;
+	} else if (strcmp(target_service, self_service) == 0) {
+		s4u2proxy = false;
+	} else {
+		s4u2proxy = true;
+	}
+
+	/*
 	 * For S4U2Self we need our own service principal,
 	 * which belongs to our own realm (available on
 	 * our client principal).
@@ -197,6 +221,14 @@
 		return code;
 	}
 
+	if (s4u2proxy) {
+		/*
+		 * If we want S4U2Proxy, we need the forwardable flag
+		 * on the S4U2Self ticket.
+		 */
+		krb5_get_creds_opt_set_options(ctx, options, KRB5_GC_FORWARDABLE);
+	}
+
 	code = krb5_get_creds_opt_set_impersonate(ctx, options,
 						  impersonate_principal);
 	if (code != 0) {
@@ -211,8 +243,118 @@
 			      self_princ, &s4u2self_creds);
 	krb5_get_creds_opt_free(ctx, options);
 	krb5_free_principal(ctx, self_princ);
+	if (code != 0) {
+		krb5_free_principal(ctx, blacklist_principal);
+		krb5_cc_destroy(ctx, tmp_cc);
+		return code;
+	}
+
+	if (!s4u2proxy) {
+		krb5_cc_destroy(ctx, tmp_cc);
+
+		/*
+		 * 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) {
+			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;
+		goto store;
+	}
+
+	/*
+	 * We are trying S4U2Proxy:
+	 *
+	 * We need the ticket from the S4U2Self step
+	 * and our TGT in order to get the delegated ticket.
+	 */
+	code = decode_Ticket((const uint8_t *)s4u2self_creds->ticket.data,
+			     s4u2self_creds->ticket.length,
+			     &s4u2self_ticket,
+			     &s4u2self_ticketlen);
+	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
+	 * our client principal).
+	 */
+	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;
+	}
+
+	code = krb5_principal_set_realm(ctx, target_princ, self_realm);
+	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;
+	}
+
+	code = krb5_get_creds_opt_alloc(ctx, &options);
+	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;
+	}
+
+	krb5_get_creds_opt_set_options(ctx, options, KRB5_GC_FORWARDABLE);
+	krb5_get_creds_opt_set_options(ctx, options, KRB5_GC_CONSTRAINED_DELEGATION);
+
+	code = krb5_get_creds_opt_set_ticket(ctx, options, &s4u2self_ticket);
+	free_Ticket(&s4u2self_ticket);
+	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;
+	}
+
+	code = krb5_get_creds(ctx, options, tmp_cc,
+			      target_princ, &s4u2proxy_creds);
+	krb5_get_creds_opt_free(ctx, options);
+	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;
 	}
@@ -222,10 +364,11 @@
 	 * and creds instead of the TGT related stuff
 	 * in the krb5_ccache of the caller.
 	 */
-	code = krb5_copy_creds_contents(ctx, s4u2self_creds,
+	code = krb5_copy_creds_contents(ctx, s4u2proxy_creds,
 					&store_creds);
-	krb5_free_creds(ctx, s4u2self_creds);
+	krb5_free_creds(ctx, s4u2proxy_creds);
 	if (code != 0) {
+		krb5_free_principal(ctx, whitelist_principal);
 		krb5_free_principal(ctx, blacklist_principal);
 		return code;
 	}
@@ -259,6 +402,7 @@
 		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;
@@ -267,6 +411,35 @@
 		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);
diff --git a/source4/auth/kerberos/kerberos.h b/source4/auth/kerberos/kerberos.h
index c712569..31794b8 100644
--- a/source4/auth/kerberos/kerberos.h
+++ b/source4/auth/kerberos/kerberos.h
@@ -97,7 +97,9 @@ krb5_error_code ads_krb5_mk_req(krb5_context context,
 bool get_auth_data_from_tkt(TALLOC_CTX *mem_ctx, DATA_BLOB *auth_data, krb5_ticket *tkt);
 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_principal impersonate_principal,
+					   const char *self_service,
+					   const char *target_service,
 					   krb5_get_init_creds_opt *krb_options,
 					   time_t *expire_time, time_t *kdc_time);
 krb5_error_code kerberos_kinit_keyblock_cc(krb5_context ctx, krb5_ccache cc,
diff --git a/source4/auth/kerberos/kerberos_util.c b/source4/auth/kerberos/kerberos_util.c
index 9cef977..9a48e95 100644
--- a/source4/auth/kerberos/kerberos_util.c
+++ b/source4/auth/kerberos/kerberos_util.c
@@ -408,6 +408,7 @@ krb5_error_code principal_from_credentials(TALLOC_CTX *parent_ctx,
 							 princ, password,
 							 impersonate_principal,
 							 self_service,
+							 target_service,
 							 krb_options,
 							 NULL, &kdc_time);
 		} else if (impersonate_principal) {
diff --git a/source4/ntvfs/cifs/vfs_cifs.c b/source4/ntvfs/cifs/vfs_cifs.c
index 24dee76..91ca08d 100644
--- a/source4/ntvfs/cifs/vfs_cifs.c
+++ b/source4/ntvfs/cifs/vfs_cifs.c
@@ -99,10 +99,12 @@ NTSTATUS ntvfs_cifs_init(void);
 #define CIFS_DOMAIN		"cifs:domain"
 #define CIFS_SHARE		"cifs:share"
 #define CIFS_USE_MACHINE_ACCT	"cifs:use-machine-account"
+#define CIFS_USE_S4U2PROXY	"cifs:use-s4u2proxy"
 #define CIFS_MAP_GENERIC	"cifs:map-generic"
 #define CIFS_MAP_TRANS2		"cifs:map-trans2"
 
 #define CIFS_USE_MACHINE_ACCT_DEFAULT	false
+#define CIFS_USE_S4U2PROXY_DEFAULT	false
 #define CIFS_MAP_GENERIC_DEFAULT	false
 #define CIFS_MAP_TRANS2_DEFAULT		true
 
@@ -150,6 +152,7 @@ static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs,
 
 	struct cli_credentials *credentials;
 	bool machine_account;
+	bool s4u2proxy;
 	const char* sharename;
 
 	switch (tcon->generic.level) {
@@ -187,6 +190,7 @@ static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs,
 	}
 
 	machine_account = share_bool_option(scfg, CIFS_USE_MACHINE_ACCT, CIFS_USE_MACHINE_ACCT_DEFAULT);
+	s4u2proxy = share_bool_option(scfg, CIFS_USE_S4U2PROXY, CIFS_USE_S4U2PROXY_DEFAULT);
 
 	p = talloc_zero(ntvfs, struct cvfs_private);
 	if (!p) {
@@ -226,6 +230,51 @@ static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs,
 	} else if (req->session_info->credentials) {
 		DEBUG(5, ("CIFS backend: Using delegated credentials\n"));
 		credentials = req->session_info->credentials;
+	} else if (s4u2proxy) {
+		struct ccache_container *ccc = NULL;
+		const char *err_str = NULL;
+		int ret;
+		char *impersonate_principal;
+		char *self_service;
+		char *target_service;
+
+		impersonate_principal = talloc_asprintf(req, "%s@%s",
+						req->session_info->info->account_name,
+						req->session_info->info->domain_name);
+
+		self_service = talloc_asprintf(req, "cifs/%s",
+					       lpcfg_netbios_name(ntvfs->ctx->lp_ctx));
+
+		target_service = talloc_asprintf(req, "cifs/%s", host);
+
+		DEBUG(5, ("CIFS backend: Using S4U2Proxy credentials\n"));
+
+		credentials = cli_credentials_init(p);
+		cli_credentials_set_conf(credentials, ntvfs->ctx->lp_ctx);
+		if (domain) {
+			cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
+		}
+		status = cli_credentials_set_machine_account(credentials, ntvfs->ctx->lp_ctx);
+		if (!NT_STATUS_IS_OK(status)) {
+			return status;
+		}
+		cli_credentials_invalidate_ccache(credentials, CRED_SPECIFIED);
+		cli_credentials_set_impersonate_principal(credentials,
+							  impersonate_principal,
+							  self_service);
+		cli_credentials_set_target_service(credentials, target_service);
+		ret = cli_credentials_get_ccache(credentials,
+						 ntvfs->ctx->event_ctx,
+						 ntvfs->ctx->lp_ctx,
+						 &ccc,
+						 &err_str);
+		if (ret != 0) {
+			status = NT_STATUS_CROSSREALM_DELEGATION_FAILURE;
+			DEBUG(1,("S4U2Proxy: cli_credentials_get_ccache() gave: ret[%d] str[%s] - %s\n",
+				ret, err_str, nt_errstr(status)));
+			return status;
+		}
+
 	} else {
 		DEBUG(1,("CIFS backend: NO delegated credentials found: You must supply server, user and password or the client must supply delegated credentials\n"));
 		return NT_STATUS_INTERNAL_ERROR;


-- 
Samba Shared Repository


More information about the samba-cvs mailing list