s4:credentials Make the CCACHE in credentials depend on the things that built it
authorAndrew Bartlett <abartlet@samba.org>
Sat, 1 May 2010 00:33:08 +0000 (10:33 +1000)
committerAndrew Bartlett <abartlet@samba.org>
Sat, 1 May 2010 20:54:23 +0000 (06:54 +1000)
This means that we consider the ccache only as reliable as the least
specified of the inputs we used.

This means that we will regenerate the ccache if any of the inputs change.

Andrew Bartlett

source4/auth/credentials/credentials.c
source4/auth/credentials/credentials_krb5.c
source4/auth/credentials/credentials_krb5.h
source4/auth/gensec/gensec_gssapi.c
source4/auth/gensec/gensec_krb5.c
source4/auth/kerberos/kerberos.h
source4/auth/kerberos/kerberos_credentials.h [new file with mode: 0644]
source4/auth/kerberos/kerberos_util.c

index 5f2658d5bd5eabb6f3e9af50121ed1a2cfe1231d..6f7630a2064a8ebc0dca1f13503bd352bc65a7f1 100644 (file)
@@ -222,7 +222,7 @@ _PUBLIC_ const char *cli_credentials_get_bind_dn(struct cli_credentials *cred)
  * @retval The username set on this context.
  * @note Return value will never be NULL except by programmer error.
  */
-_PUBLIC_ const char *cli_credentials_get_principal(struct cli_credentials *cred, TALLOC_CTX *mem_ctx)
+const char *cli_credentials_get_principal_and_obtained(struct cli_credentials *cred, TALLOC_CTX *mem_ctx, enum credentials_obtained *obtained)
 {
        if (cred->machine_account_pending) {
                cli_credentials_set_machine_account(cred,
@@ -238,20 +238,36 @@ _PUBLIC_ const char *cli_credentials_get_principal(struct cli_credentials *cred,
                cli_credentials_invalidate_ccache(cred, cred->principal_obtained);
        }
 
-       if (cred->principal_obtained < cred->username_obtained) {
+       if (cred->principal_obtained < cred->username_obtained
+           || cred->principal_obtained < MAX(cred->domain_obtained, cred->realm_obtained)) {
                if (cred->domain_obtained > cred->realm_obtained) {
+                       *obtained = MIN(cred->domain_obtained, cred->username_obtained);
                        return talloc_asprintf(mem_ctx, "%s@%s", 
                                               cli_credentials_get_username(cred),
                                               cli_credentials_get_domain(cred));
                } else {
+                       *obtained = MIN(cred->domain_obtained, cred->username_obtained);
                        return talloc_asprintf(mem_ctx, "%s@%s", 
                                               cli_credentials_get_username(cred),
                                               cli_credentials_get_realm(cred));
                }
        }
+       *obtained = cred->principal_obtained;
        return talloc_reference(mem_ctx, cred->principal);
 }
 
+/**
+ * Obtain the client principal for this credentials context.
+ * @param cred credentials context
+ * @retval The username set on this context.
+ * @note Return value will never be NULL except by programmer error.
+ */
+_PUBLIC_ const char *cli_credentials_get_principal(struct cli_credentials *cred, TALLOC_CTX *mem_ctx)
+{
+       enum credentials_obtained obtained;
+       return cli_credentials_get_principal_and_obtained(cred, mem_ctx, &obtained);
+}
+
 bool cli_credentials_set_principal(struct cli_credentials *cred, 
                                   const char *val, 
                                   enum credentials_obtained obtained)
index d76073093b4b04cfde76e31de5f4ce7afd11f00d..12bf610bf8e905ed646427dd573ac35efabcbb9a 100644 (file)
@@ -27,6 +27,7 @@
 #include "auth/credentials/credentials.h"
 #include "auth/credentials/credentials_proto.h"
 #include "auth/credentials/credentials_krb5.h"
+#include "auth/kerberos/kerberos_credentials.h"
 #include "param/param.h"
 
 _PUBLIC_ int cli_credentials_get_krb5_context(struct cli_credentials *cred, 
@@ -282,6 +283,7 @@ _PUBLIC_ int cli_credentials_get_named_ccache(struct cli_credentials *cred,
                                              const char **error_string)
 {
        krb5_error_code ret;
+       enum credentials_obtained obtained;
        
        if (cred->machine_account_pending) {
                cli_credentials_set_machine_account(cred, lp_ctx);
@@ -302,15 +304,13 @@ _PUBLIC_ int cli_credentials_get_named_ccache(struct cli_credentials *cred,
                return ret;
        }
 
-       ret = kinit_to_ccache(cred, cred, (*ccc)->smb_krb5_context, (*ccc)->ccache, error_string);
+       ret = kinit_to_ccache(cred, cred, (*ccc)->smb_krb5_context, (*ccc)->ccache, &obtained, error_string);
        if (ret) {
                return ret;
        }
 
        ret = cli_credentials_set_from_ccache(cred, *ccc, 
-                                             (MAX(MAX(cred->principal_obtained, 
-                                                      cred->username_obtained), 
-                                                  cred->password_obtained)), error_string);
+                                             obtained, error_string);
        
        cred->ccache = *ccc;
        cred->ccache_obtained = cred->principal_obtained;
@@ -330,6 +330,16 @@ _PUBLIC_ int cli_credentials_get_ccache(struct cli_credentials *cred,
        return cli_credentials_get_named_ccache(cred, event_ctx, lp_ctx, NULL, ccc, error_string);
 }
 
+/* We have good reason to think the ccache in these credentials is invalid - blow it away */
+static void cli_credentials_unconditionally_invalidate_client_gss_creds(struct cli_credentials *cred)
+{
+       if (cred->client_gss_creds_obtained > CRED_UNINITIALISED) {
+               talloc_unlink(cred, cred->client_gss_creds);
+               cred->client_gss_creds = NULL;
+       }
+       cred->client_gss_creds_obtained = CRED_UNINITIALISED;
+}
+
 void cli_credentials_invalidate_client_gss_creds(struct cli_credentials *cred, 
                                                 enum credentials_obtained obtained)
 {
@@ -351,6 +361,18 @@ void cli_credentials_invalidate_client_gss_creds(struct cli_credentials *cred,
        }
 }
 
+/* We have good reason to think this CCACHE is invalid.  Blow it away */
+static void cli_credentials_unconditionally_invalidate_ccache(struct cli_credentials *cred)
+{
+       if (cred->ccache_obtained > CRED_UNINITIALISED) {
+               talloc_unlink(cred, cred->ccache);
+               cred->ccache = NULL;
+       }
+       cred->ccache_obtained = CRED_UNINITIALISED;
+
+       cli_credentials_unconditionally_invalidate_client_gss_creds(cred);
+}
+
 _PUBLIC_ void cli_credentials_invalidate_ccache(struct cli_credentials *cred, 
                                       enum credentials_obtained obtained)
 {
@@ -416,6 +438,23 @@ _PUBLIC_ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred,
 
        maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL, 
                                        &gcc->creds);
+       if ((maj_stat == GSS_S_FAILURE) && (min_stat == (OM_uint32)KRB5_CC_END || min_stat == (OM_uint32) KRB5_CC_NOTFOUND)) {
+               /* This CCACHE is no good.  Ensure we don't use it again */
+               cli_credentials_unconditionally_invalidate_ccache(cred);
+
+               /* Now try again to get a ccache */
+               ret = cli_credentials_get_ccache(cred, event_ctx, lp_ctx,
+                                                &ccache, error_string);
+               if (ret) {
+                       DEBUG(1, ("Failed to re-get CCACHE for GSSAPI client: %s\n", error_message(ret)));
+                       return ret;
+               }
+
+               maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL,
+                                               &gcc->creds);
+
+       }
+
        if (maj_stat) {
                talloc_free(gcc);
                if (min_stat) {
@@ -698,12 +737,11 @@ _PUBLIC_ int cli_credentials_get_server_gss_creds(struct cli_credentials *cred,
        TALLOC_CTX *mem_ctx;
        krb5_principal princ;
        const char *error_string;
+       enum credentials_obtained obtained;
 
-       if (cred->server_gss_creds_obtained >= (MAX(cred->keytab_obtained, 
-                                                   MAX(cred->principal_obtained, 
-                                                       cred->username_obtained)))) {
-               *_gcc = cred->server_gss_creds;
-               return 0;
+       mem_ctx = talloc_new(cred);
+       if (!mem_ctx) {
+               return ENOMEM;
        }
 
        ret = cli_credentials_get_krb5_context(cred, event_ctx, lp_ctx, &smb_krb5_context);
@@ -711,22 +749,23 @@ _PUBLIC_ int cli_credentials_get_server_gss_creds(struct cli_credentials *cred,
                return ret;
        }
 
-       ret = cli_credentials_get_keytab(cred, event_ctx, lp_ctx, &ktc);
+       ret = principal_from_credentials(mem_ctx, cred, smb_krb5_context, &princ, &obtained, &error_string);
        if (ret) {
-               DEBUG(1, ("Failed to get keytab for GSSAPI server: %s\n", error_message(ret)));
+               DEBUG(1,("cli_credentials_get_server_gss_creds: makeing krb5 principal failed (%s)\n",
+                        error_string));
+               talloc_free(mem_ctx);
                return ret;
        }
 
-       mem_ctx = talloc_new(cred);
-       if (!mem_ctx) {
-               return ENOMEM;
+       if (cred->server_gss_creds_obtained >= (MAX(cred->keytab_obtained, obtained))) {
+               talloc_free(mem_ctx);
+               *_gcc = cred->server_gss_creds;
+               return 0;
        }
 
-       ret = principal_from_credentials(mem_ctx, cred, smb_krb5_context, &princ, &error_string);
+       ret = cli_credentials_get_keytab(cred, event_ctx, lp_ctx, &ktc);
        if (ret) {
-               DEBUG(1,("cli_credentials_get_server_gss_creds: makeing krb5 principal failed (%s)\n",
-                        error_string));
-               talloc_free(mem_ctx);
+               DEBUG(1, ("Failed to get keytab for GSSAPI server: %s\n", error_message(ret)));
                return ret;
        }
 
index 72a437360995c06c1c338e0c32ec6e20cf9a06a4..3a614ff30efe8e82d29ed16ba032a7e364943820 100644 (file)
@@ -44,6 +44,12 @@ krb5_error_code principal_from_credentials(TALLOC_CTX *parent_ctx,
                                           struct cli_credentials *credentials, 
                                           struct smb_krb5_context *smb_krb5_context,
                                           krb5_principal *princ,
+                                          enum credentials_obtained *obtained,
                                           const char **error_string);
+krb5_error_code impersonate_principal_from_credentials(TALLOC_CTX *parent_ctx,
+                                                      struct cli_credentials *credentials,
+                                                      struct smb_krb5_context *smb_krb5_context,
+                                                      krb5_principal *princ,
+                                                      const char **error_string);
        
 #endif /* __CREDENTIALS_KRB5_H__ */
index 9e974cb941e9f5f5a67e882fed7905f557b94642..c6901a7b5eab8181a931d84db3ef68aa1382efcb 100644 (file)
@@ -379,6 +379,10 @@ static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_securi
        case KRB5_KDC_UNREACH:
                DEBUG(3, ("Cannot reach a KDC we require to contact %s : %s\n", principal, error_string));
                return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
+       case KRB5_CC_NOTFOUND:
+       case KRB5_CC_END:
+               DEBUG(3, ("Error preparing credentials we require to contact %s : %s\n", principal, error_string));
+               return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
        default:
                DEBUG(1, ("Aquiring initiator credentials failed: %s\n", error_string));
                return NT_STATUS_UNSUCCESSFUL;
index bb9ace70b1d44c29431b7503c2a7cc3fd73cda98..c2f96d7b7fc9c3a314fb3e4e65fbb17a30309811 100644 (file)
@@ -31,6 +31,8 @@
 #include "lib/tsocket/tsocket.h"
 #include "librpc/rpc/dcerpc.h"
 #include "auth/credentials/credentials.h"
+#include "auth/credentials/credentials_krb5.h"
+#include "auth/kerberos/kerberos_credentials.h"
 #include "auth/gensec/gensec.h"
 #include "auth/gensec/gensec_proto.h"
 #include "param/param.h"
@@ -287,6 +289,10 @@ static NTSTATUS gensec_krb5_common_client_start(struct gensec_security *gensec_s
        case KRB5_KDC_UNREACH:
                DEBUG(3, ("Cannot reach a KDC we require to contact %s: %s\n", principal, error_string));
                return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
+       case KRB5_CC_NOTFOUND:
+       case KRB5_CC_END:
+               DEBUG(3, ("Error preparing credentials we require to contact %s : %s\n", principal, error_string));
+               return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
        default:
                DEBUG(1, ("gensec_krb5_start: Aquiring initiator credentials failed: %s\n", error_string));
                return NT_STATUS_UNSUCCESSFUL;
@@ -474,6 +480,7 @@ static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security,
                struct keytab_container *keytab;
                krb5_principal server_in_keytab;
                const char *error_string;
+               enum credentials_obtained obtained;
 
                if (!in.data) {
                        return NT_STATUS_INVALID_PARAMETER;
@@ -490,7 +497,7 @@ static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security,
                /* This ensures we lookup the correct entry in that keytab */
                ret = principal_from_credentials(out_mem_ctx, gensec_get_credentials(gensec_security), 
                                                 gensec_krb5_state->smb_krb5_context, 
-                                                &server_in_keytab, &error_string);
+                                                &server_in_keytab, &obtained, &error_string);
 
                if (ret) {
                        DEBUG(2,("Failed to make credentials from principal: %s\n", error_string));
index 992b509dbf70d95ea894e0252fd601fd4950af61..1990343808e93786656752a216f7fe22389294d9 100644 (file)
@@ -104,21 +104,6 @@ bool kerberos_compatible_enctypes(krb5_context context, krb5_enctype enctype1, k
 void kerberos_free_data_contents(krb5_context context, krb5_data *pdata);
 krb5_error_code smb_krb5_kt_free_entry(krb5_context context, krb5_keytab_entry *kt_entry);
 char *smb_get_krb5_error_message(krb5_context context, krb5_error_code code, TALLOC_CTX *mem_ctx);
- krb5_error_code kinit_to_ccache(TALLOC_CTX *parent_ctx,
-                                struct cli_credentials *credentials,
-                                struct smb_krb5_context *smb_krb5_context,
-                                krb5_ccache ccache,
-                                const char **error_string);
-krb5_error_code impersonate_principal_from_credentials(TALLOC_CTX *parent_ctx,
-                                                      struct cli_credentials *credentials,
-                                                      struct smb_krb5_context *smb_krb5_context,
-                                                      krb5_principal *princ,
-                                                      const char **error_string);
-krb5_error_code principal_from_credentials(TALLOC_CTX *parent_ctx, 
-                                          struct cli_credentials *credentials, 
-                                          struct smb_krb5_context *smb_krb5_context,
-                                          krb5_principal *princ,
-                                          const char **error_string);
 NTSTATUS kerberos_decode_pac(TALLOC_CTX *mem_ctx,
                             struct smb_iconv_convenience *iconv_convenience,
                             struct PAC_DATA **pac_data_out,
diff --git a/source4/auth/kerberos/kerberos_credentials.h b/source4/auth/kerberos/kerberos_credentials.h
new file mode 100644 (file)
index 0000000..5522775
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Kerberos utility functions for GENSEC
+
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2010
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+krb5_error_code kinit_to_ccache(TALLOC_CTX *parent_ctx,
+                                struct cli_credentials *credentials,
+                                struct smb_krb5_context *smb_krb5_context,
+                                krb5_ccache ccache,
+                                enum credentials_obtained *obtained,
+                                const char **error_string);
index 44d97b7f08f787d6cca1e6910f7c430cf558b69c..2b358515f871558c9cbb5dde18b19daad7b35c5d 100644 (file)
@@ -26,6 +26,7 @@
 #include "auth/credentials/credentials.h"
 #include "auth/credentials/credentials_proto.h"
 #include "auth/credentials/credentials_krb5.h"
+#include "auth/kerberos/kerberos_credentials.h"
 
 struct principal_container {
        struct smb_krb5_context *smb_krb5_context;
@@ -143,6 +144,7 @@ static krb5_error_code salt_principal_from_credentials(TALLOC_CTX *parent_ctx,
                                            struct cli_credentials *credentials, 
                                            struct smb_krb5_context *smb_krb5_context,
                                            krb5_principal *princ,
+                                           enum credentials_obtained *obtained,
                                            const char **error_string)
 {
        krb5_error_code ret;
@@ -152,7 +154,7 @@ static krb5_error_code salt_principal_from_credentials(TALLOC_CTX *parent_ctx,
                (*error_string) = error_message(ENOMEM);
                return ENOMEM;
        }
-       princ_string = cli_credentials_get_principal(credentials, mem_ctx);
+       princ_string = cli_credentials_get_principal_and_obtained(credentials, mem_ctx, obtained);
        if (!princ_string) {
                (*error_string) = error_message(ENOMEM);
                return ENOMEM;
@@ -188,6 +190,7 @@ static krb5_error_code salt_principal_from_credentials(TALLOC_CTX *parent_ctx,
                                 struct cli_credentials *credentials,
                                 struct smb_krb5_context *smb_krb5_context,
                                 krb5_ccache ccache,
+                                enum credentials_obtained *obtained,
                                 const char **error_string)
 {
        krb5_error_code ret;
@@ -203,7 +206,7 @@ static krb5_error_code salt_principal_from_credentials(TALLOC_CTX *parent_ctx,
                return ENOMEM;
        }
 
-       ret = principal_from_credentials(mem_ctx, credentials, smb_krb5_context, &princ, error_string);
+       ret = principal_from_credentials(mem_ctx, credentials, smb_krb5_context, &princ, obtained, error_string);
        if (ret) {
                talloc_free(mem_ctx);
                return ret;
@@ -285,7 +288,8 @@ static krb5_error_code salt_principal_from_credentials(TALLOC_CTX *parent_ctx,
                ret = kinit_to_ccache(parent_ctx,
                                      credentials,
                                      smb_krb5_context,
-                                     ccache, error_string);
+                                     ccache, obtained,
+                                     error_string);
        }
        if (ret) {
                (*error_string) = talloc_asprintf(credentials, "kinit for %s failed (%s)\n",
@@ -410,6 +414,7 @@ static krb5_error_code create_keytab(TALLOC_CTX *parent_ctx,
        krb5_principal princ;
        const char *princ_string;
        const char *error_string;
+       enum credentials_obtained obtained;
 
        TALLOC_CTX *mem_ctx = talloc_new(parent_ctx);
        if (!mem_ctx) {
@@ -418,7 +423,7 @@ static krb5_error_code create_keytab(TALLOC_CTX *parent_ctx,
 
        princ_string = cli_credentials_get_principal(machine_account, mem_ctx);
        /* Get the principal we will store the new keytab entries under */
-       ret = principal_from_credentials(mem_ctx, machine_account, smb_krb5_context, &princ, &error_string);
+       ret = principal_from_credentials(mem_ctx, machine_account, smb_krb5_context, &princ, &obtained, &error_string);
        if (ret) {
                DEBUG(1,("create_keytab: makeing krb5 principal failed (%s)\n", error_string));
                talloc_free(mem_ctx);
@@ -549,6 +554,7 @@ static krb5_error_code remove_old_entries(TALLOC_CTX *parent_ctx,
        TALLOC_CTX *mem_ctx = talloc_new(parent_ctx);
        const char *princ_string;
        const char *error_string;
+       enum credentials_obtained obtained;
 
        if (!mem_ctx) {
                return ENOMEM;
@@ -558,7 +564,7 @@ static krb5_error_code remove_old_entries(TALLOC_CTX *parent_ctx,
        princ_string = cli_credentials_get_principal(machine_account, mem_ctx);
 
        /* Get the principal we will store the new keytab entries under */
-       ret = principal_from_credentials(mem_ctx, machine_account, smb_krb5_context, &princ, &error_string);
+       ret = principal_from_credentials(mem_ctx, machine_account, smb_krb5_context, &princ, &obtained, &error_string);
        if (ret) {
                DEBUG(1,("update_keytab: makeing krb5 principal failed (%s)\n", error_string));
                talloc_free(mem_ctx);