[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