summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/auth/credentials/credentials.c20
-rw-r--r--source4/auth/credentials/credentials_krb5.c75
-rw-r--r--source4/auth/credentials/credentials_krb5.h6
-rw-r--r--source4/auth/gensec/gensec_gssapi.c4
-rw-r--r--source4/auth/gensec/gensec_krb5.c9
-rw-r--r--source4/auth/kerberos/kerberos.h15
-rw-r--r--source4/auth/kerberos/kerberos_credentials.h28
-rw-r--r--source4/auth/kerberos/kerberos_util.c16
8 files changed, 132 insertions, 41 deletions
diff --git a/source4/auth/credentials/credentials.c b/source4/auth/credentials/credentials.c
index 5f2658d5bd..6f7630a206 100644
--- a/source4/auth/credentials/credentials.c
+++ b/source4/auth/credentials/credentials.c
@@ -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)
diff --git a/source4/auth/credentials/credentials_krb5.c b/source4/auth/credentials/credentials_krb5.c
index d76073093b..12bf610bf8 100644
--- a/source4/auth/credentials/credentials_krb5.c
+++ b/source4/auth/credentials/credentials_krb5.c
@@ -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;
}
diff --git a/source4/auth/credentials/credentials_krb5.h b/source4/auth/credentials/credentials_krb5.h
index 72a4373609..3a614ff30e 100644
--- a/source4/auth/credentials/credentials_krb5.h
+++ b/source4/auth/credentials/credentials_krb5.h
@@ -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__ */
diff --git a/source4/auth/gensec/gensec_gssapi.c b/source4/auth/gensec/gensec_gssapi.c
index 9e974cb941..c6901a7b5e 100644
--- a/source4/auth/gensec/gensec_gssapi.c
+++ b/source4/auth/gensec/gensec_gssapi.c
@@ -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;
diff --git a/source4/auth/gensec/gensec_krb5.c b/source4/auth/gensec/gensec_krb5.c
index bb9ace70b1..c2f96d7b7f 100644
--- a/source4/auth/gensec/gensec_krb5.c
+++ b/source4/auth/gensec/gensec_krb5.c
@@ -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));
diff --git a/source4/auth/kerberos/kerberos.h b/source4/auth/kerberos/kerberos.h
index 992b509dbf..1990343808 100644
--- a/source4/auth/kerberos/kerberos.h
+++ b/source4/auth/kerberos/kerberos.h
@@ -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
index 0000000000..55227752e3
--- /dev/null
+++ b/source4/auth/kerberos/kerberos_credentials.h
@@ -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);
diff --git a/source4/auth/kerberos/kerberos_util.c b/source4/auth/kerberos/kerberos_util.c
index 44d97b7f08..2b358515f8 100644
--- a/source4/auth/kerberos/kerberos_util.c
+++ b/source4/auth/kerberos/kerberos_util.c
@@ -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);