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 <me...@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 <me...@samba.org>
    Autobuild-Date: Wed Jun 22 18:17:43 CEST 2011 on sn-devel-104

commit 033f3376a834c1078b377647069b7e30aef59667
Author: Stefan Metzmacher <me...@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 <me...@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

Reply via email to