summaryrefslogtreecommitdiff
path: root/source4/auth/credentials
diff options
context:
space:
mode:
Diffstat (limited to 'source4/auth/credentials')
-rw-r--r--source4/auth/credentials/credentials.c27
-rw-r--r--source4/auth/credentials/credentials.h6
-rw-r--r--source4/auth/credentials/credentials_files.c92
-rw-r--r--source4/auth/credentials/credentials_krb5.c211
4 files changed, 314 insertions, 22 deletions
diff --git a/source4/auth/credentials/credentials.c b/source4/auth/credentials/credentials.c
index 86a3df0077..75c6795e73 100644
--- a/source4/auth/credentials/credentials.c
+++ b/source4/auth/credentials/credentials.c
@@ -46,7 +46,8 @@ struct cli_credentials *cli_credentials_init(TALLOC_CTX *mem_ctx)
cred->domain_obtained = CRED_UNINITIALISED;
cred->realm_obtained = CRED_UNINITIALISED;
cred->ccache_obtained = CRED_UNINITIALISED;
- cred->gss_creds_obtained = CRED_UNINITIALISED;
+ cred->client_gss_creds_obtained = CRED_UNINITIALISED;
+ cred->server_gss_creds_obtained = CRED_UNINITIALISED;
cred->keytab_obtained = CRED_UNINITIALISED;
cred->principal_obtained = CRED_UNINITIALISED;
@@ -148,6 +149,9 @@ BOOL cli_credentials_set_principal(struct cli_credentials *cred,
return False;
}
+/* Set a callback to get the principal. This could be a popup dialog,
+ * a terminal prompt or similar. */
+
BOOL cli_credentials_set_principal_callback(struct cli_credentials *cred,
const char *(*principal_cb) (struct cli_credentials *))
{
@@ -160,6 +164,10 @@ BOOL cli_credentials_set_principal_callback(struct cli_credentials *cred,
return False;
}
+/* Some of our tools are 'anonymous by default'. This is a single
+ * function to determine if authentication has been explicitly
+ * requested */
+
BOOL cli_credentials_authentication_requested(struct cli_credentials *cred)
{
if (cred->principal_obtained >= CRED_SPECIFIED) {
@@ -190,6 +198,9 @@ const char *cli_credentials_get_password(struct cli_credentials *cred)
return cred->password;
}
+/* Set a password on the credentials context, including an indication
+ * of 'how' the password was obtained */
+
BOOL cli_credentials_set_password(struct cli_credentials *cred,
const char *val,
enum credentials_obtained obtained)
@@ -240,7 +251,11 @@ BOOL cli_credentials_set_old_password(struct cli_credentials *cred,
}
/**
- * Obtain the password for this credentials context.
+ * Obtain the password, in the form MD4(unicode(password)) for this credentials context.
+ *
+ * Sometimes we only have this much of the password, while the rest of
+ * the time this call avoids calling E_md4hash themselves.
+ *
* @param cred credentials context
* @retval If set, the cleartext password, otherwise NULL
*/
@@ -566,7 +581,13 @@ void cli_credentials_set_anonymous(struct cli_credentials *cred)
BOOL cli_credentials_is_anonymous(struct cli_credentials *cred)
{
- const char *username = cli_credentials_get_username(cred);
+ const char *username;
+
+ if (cred->machine_account_pending) {
+ cli_credentials_set_machine_account(cred);
+ }
+
+ username = cli_credentials_get_username(cred);
/* Yes, it is deliberate that we die if we have a NULL pointer
* here - anonymous is "", not NULL, which is 'never specified,
diff --git a/source4/auth/credentials/credentials.h b/source4/auth/credentials/credentials.h
index 3e84db52a5..81773aa70a 100644
--- a/source4/auth/credentials/credentials.h
+++ b/source4/auth/credentials/credentials.h
@@ -47,9 +47,10 @@ struct cli_credentials {
enum credentials_obtained domain_obtained;
enum credentials_obtained realm_obtained;
enum credentials_obtained ccache_obtained;
- enum credentials_obtained gss_creds_obtained;
+ enum credentials_obtained client_gss_creds_obtained;
enum credentials_obtained principal_obtained;
enum credentials_obtained keytab_obtained;
+ enum credentials_obtained server_gss_creds_obtained;
const char *workstation;
const char *username;
@@ -63,8 +64,9 @@ struct cli_credentials {
struct samr_Password *nt_hash;
struct ccache_container *ccache;
- struct gssapi_creds_container *gssapi_creds;
+ struct gssapi_creds_container *client_gss_creds;
struct keytab_container *keytab;
+ struct gssapi_creds_container *server_gss_creds;
const char *(*workstation_cb) (struct cli_credentials *);
const char *(*password_cb) (struct cli_credentials *);
diff --git a/source4/auth/credentials/credentials_files.c b/source4/auth/credentials/credentials_files.c
index 35bbc43b34..6b3c77c4e3 100644
--- a/source4/auth/credentials/credentials_files.c
+++ b/source4/auth/credentials/credentials_files.c
@@ -164,9 +164,9 @@ BOOL cli_credentials_parse_file(struct cli_credentials *cred, const char *file,
* @param cred Credentials structure to fill in
* @retval NTSTATUS error detailing any failure
*/
-static NTSTATUS cli_credentials_set_secrets(struct cli_credentials *cred,
- const char *base,
- const char *filter)
+NTSTATUS cli_credentials_set_secrets(struct cli_credentials *cred,
+ const char *base,
+ const char *filter)
{
TALLOC_CTX *mem_ctx;
@@ -183,6 +183,8 @@ static NTSTATUS cli_credentials_set_secrets(struct cli_credentials *cred,
"ntPwdHash",
"msDS-KeyVersionNumber",
"saltPrincipal",
+ "privateKeytab",
+ "krb5Keytab",
NULL
};
@@ -193,6 +195,7 @@ static NTSTATUS cli_credentials_set_secrets(struct cli_credentials *cred,
const char *realm;
enum netr_SchannelType sct;
const char *salt_principal;
+ const char *keytab;
/* ok, we are going to get it now, don't recurse back here */
cred->machine_account_pending = False;
@@ -201,6 +204,7 @@ static NTSTATUS cli_credentials_set_secrets(struct cli_credentials *cred,
cred->machine_account = True;
mem_ctx = talloc_named(cred, 0, "cli_credentials fetch machine password");
+
/* Local secrets are stored in secrets.ldb */
ldb = secrets_db_connect(mem_ctx);
if (!ldb) {
@@ -279,7 +283,22 @@ static NTSTATUS cli_credentials_set_secrets(struct cli_credentials *cred,
}
cli_credentials_set_kvno(cred, ldb_msg_find_int(msgs[0], "msDS-KeyVersionNumber", 0));
-
+
+ /* If there was an external keytab specified by reference in
+ * the LDB, then use this. Otherwise we will make one up
+ * (chewing CPU time) from the password */
+ keytab = ldb_msg_find_string(msgs[0], "krb5Keytab", NULL);
+ if (keytab) {
+ cli_credentials_set_keytab(cred, keytab, CRED_SPECIFIED);
+ } else {
+ keytab = ldb_msg_find_string(msgs[0], "privateKeytab", NULL);
+ if (keytab) {
+ keytab = talloc_asprintf(mem_ctx, "FILE:%s", private_path(mem_ctx, keytab));
+ if (keytab) {
+ cli_credentials_set_keytab(cred, keytab, CRED_SPECIFIED);
+ }
+ }
+ }
talloc_free(mem_ctx);
return NT_STATUS_OK;
@@ -345,3 +364,68 @@ void cli_credentials_set_machine_account_pending(struct cli_credentials *cred)
cred->machine_account_pending = True;
}
+
+NTSTATUS cli_credentials_update_all_keytabs(TALLOC_CTX *parent_ctx)
+{
+ TALLOC_CTX *mem_ctx;
+ int ldb_ret;
+ struct ldb_context *ldb;
+ struct ldb_message **msgs;
+ const char *attrs[] = { NULL };
+ struct cli_credentials *creds;
+ const char *filter;
+ NTSTATUS status;
+ int i, ret;
+
+ mem_ctx = talloc_new(parent_ctx);
+ if (!mem_ctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Local secrets are stored in secrets.ldb */
+ ldb = secrets_db_connect(mem_ctx);
+ if (!ldb) {
+ DEBUG(1, ("Could not open secrets.ldb\n"));
+ talloc_free(mem_ctx);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /* search for the secret record */
+ ldb_ret = gendb_search(ldb,
+ mem_ctx, NULL,
+ &msgs, attrs,
+ "objectClass=kerberosSecret");
+ if (ldb_ret == -1) {
+ DEBUG(1, ("Error looking for kerberos type secrets to push into a keytab"));
+ talloc_free(mem_ctx);
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ for (i=0; i < ldb_ret; i++) {
+ /* Make a credentials structure from it */
+ creds = cli_credentials_init(mem_ctx);
+ if (!creds) {
+ DEBUG(1, ("cli_credentials_init failed!"));
+ talloc_free(mem_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+ cli_credentials_set_conf(creds);
+ filter = talloc_asprintf(mem_ctx, "dn=%s", ldb_dn_linearize(mem_ctx, msgs[i]->dn));
+ status = cli_credentials_set_secrets(creds, NULL, filter);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to read secrets for keytab update for %s\n",
+ filter));
+ talloc_free(mem_ctx);
+ return status;
+ }
+ ret = cli_credentials_update_keytab(creds);
+ if (ret != 0) {
+ DEBUG(1, ("Failed to update keytab for %s\n",
+ filter));
+ talloc_free(mem_ctx);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+ return NT_STATUS_OK;
+}
+
diff --git a/source4/auth/credentials/credentials_krb5.c b/source4/auth/credentials/credentials_krb5.c
index a3761e8359..173739e9b8 100644
--- a/source4/auth/credentials/credentials_krb5.c
+++ b/source4/auth/credentials/credentials_krb5.c
@@ -52,6 +52,10 @@ int cli_credentials_set_from_ccache(struct cli_credentials *cred,
char *name;
char **realm;
+ if (cred->ccache_obtained > obtained) {
+ return 0;
+ }
+
ret = krb5_cc_get_principal(cred->ccache->smb_krb5_context->krb5_context,
cred->ccache->ccache, &princ);
@@ -107,7 +111,12 @@ int cli_credentials_set_ccache(struct cli_credentials *cred,
{
krb5_error_code ret;
krb5_principal princ;
- struct ccache_container *ccc = talloc(cred, struct ccache_container);
+ struct ccache_container *ccc;
+ if (cred->ccache_obtained > obtained) {
+ return 0;
+ }
+
+ ccc = talloc(cred, struct ccache_container);
if (!ccc) {
return ENOMEM;
}
@@ -265,10 +274,10 @@ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred,
OM_uint32 maj_stat, min_stat;
struct gssapi_creds_container *gcc;
struct ccache_container *ccache;
- if (cred->gss_creds_obtained >= (MAX(cred->ccache_obtained,
+ if (cred->client_gss_creds_obtained >= (MAX(cred->ccache_obtained,
MAX(cred->principal_obtained,
cred->username_obtained)))) {
- *_gcc = cred->gssapi_creds;
+ *_gcc = cred->client_gss_creds;
return 0;
}
ret = cli_credentials_get_ccache(cred,
@@ -283,8 +292,8 @@ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred,
return ENOMEM;
}
- maj_stat = gss_krb5_import_ccache(&min_stat, ccache->ccache,
- &gcc->creds);
+ maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL,
+ &gcc->creds);
if (maj_stat) {
if (min_stat) {
ret = min_stat;
@@ -293,20 +302,20 @@ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred,
}
}
if (ret == 0) {
- cred->gss_creds_obtained = cred->ccache_obtained;
+ cred->client_gss_creds_obtained = cred->ccache_obtained;
talloc_set_destructor(gcc, free_gssapi_creds);
- cred->gssapi_creds = gcc;
+ cred->client_gss_creds = gcc;
*_gcc = gcc;
}
return ret;
}
/**
- Set a gssapi cred_id_t into the credentails system.
+ Set a gssapi cred_id_t into the credentails system. (Client case)
This grabs the credentials both 'intact' and getting the krb5
ccache out of it. This routine can be generalised in future for
- the case where we deal with GSSAPI mechs other than krb5.
+ the case where we deal with GSSAPI mechs other than krb5.
On sucess, the caller must not free gssapi_cred, as it now belongs
to the credentials system.
@@ -319,7 +328,12 @@ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred,
int ret;
OM_uint32 maj_stat, min_stat;
struct ccache_container *ccc;
- struct gssapi_creds_container *gcc = talloc(cred, struct gssapi_creds_container);
+ struct gssapi_creds_container *gcc;
+ if (cred->client_gss_creds_obtained > obtained) {
+ return 0;
+ }
+
+ gcc = talloc(cred, struct gssapi_creds_container);
if (!gcc) {
return ENOMEM;
}
@@ -346,18 +360,23 @@ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred,
gcc->creds = gssapi_cred;
talloc_set_destructor(gcc, free_gssapi_creds);
- cred->gss_creds_obtained = obtained;
- cred->gssapi_creds = gcc;
+ cred->client_gss_creds_obtained = obtained;
+ cred->client_gss_creds = gcc;
}
return ret;
}
+/* Get the keytab (actually, a container containing the krb5_keytab)
+ * attached to this context. If this hasn't been done or set before,
+ * it will be generated from the password.
+ */
int cli_credentials_get_keytab(struct cli_credentials *cred,
struct keytab_container **_ktc)
{
krb5_error_code ret;
struct keytab_container *ktc;
struct smb_krb5_context *smb_krb5_context;
+ TALLOC_CTX *mem_ctx;
if (cred->keytab_obtained >= (MAX(cred->principal_obtained,
cred->username_obtained))) {
@@ -374,16 +393,180 @@ int cli_credentials_get_keytab(struct cli_credentials *cred,
return ret;
}
- ret = create_memory_keytab(cred, cred, smb_krb5_context, &ktc);
+ mem_ctx = talloc_new(cred);
+ if (!mem_ctx) {
+ return ENOMEM;
+ }
+
+ ret = create_memory_keytab(mem_ctx, cred, smb_krb5_context, &ktc);
if (ret) {
+ talloc_free(mem_ctx);
return ret;
}
cred->keytab_obtained = (MAX(cred->principal_obtained,
cred->username_obtained));
+ talloc_steal(cred, ktc);
cred->keytab = ktc;
*_ktc = cred->keytab;
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+/* Given the name of a keytab (presumably in the format
+ * FILE:/etc/krb5.keytab), open it and attach it */
+
+int cli_credentials_set_keytab(struct cli_credentials *cred,
+ const char *keytab_name,
+ enum credentials_obtained obtained)
+{
+ krb5_error_code ret;
+ struct keytab_container *ktc;
+ struct smb_krb5_context *smb_krb5_context;
+ krb5_keytab keytab;
+ TALLOC_CTX *mem_ctx;
+
+ if (cred->keytab_obtained >= obtained) {
+ return 0;
+ }
+
+ ret = cli_credentials_get_krb5_context(cred, &smb_krb5_context);
+ if (ret) {
+ return ret;
+ }
+
+ mem_ctx = talloc_new(cred);
+ if (!mem_ctx) {
+ return ENOMEM;
+ }
+
+ ret = krb5_kt_resolve(smb_krb5_context->krb5_context, keytab_name, &keytab);
+ if (ret) {
+ DEBUG(1,("failed to open krb5 keytab: %s\n",
+ smb_get_krb5_error_message(smb_krb5_context->krb5_context,
+ ret, mem_ctx)));
+ talloc_free(mem_ctx);
+ return ret;
+ }
+
+ ktc = talloc(mem_ctx, struct keytab_container);
+ if (!ktc) {
+ talloc_free(mem_ctx);
+ return ENOMEM;
+ }
+
+ ktc->smb_krb5_context = talloc_reference(ktc, smb_krb5_context);
+ ktc->keytab = keytab;
+
+ cred->keytab_obtained = obtained;
+
+ talloc_steal(cred, ktc);
+ cred->keytab = ktc;
+ talloc_free(mem_ctx);
+
+ return ret;
+}
+
+int cli_credentials_update_keytab(struct cli_credentials *cred)
+{
+ krb5_error_code ret;
+ struct keytab_container *ktc;
+ struct smb_krb5_context *smb_krb5_context;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_new(cred);
+ if (!mem_ctx) {
+ return ENOMEM;
+ }
+
+ ret = cli_credentials_get_krb5_context(cred, &smb_krb5_context);
+ if (ret) {
+ talloc_free(mem_ctx);
+ return ret;
+ }
+
+ ret = cli_credentials_get_keytab(cred, &ktc);
+ if (ret != 0) {
+ talloc_free(mem_ctx);
+ return ret;
+ }
+
+ ret = update_keytab(mem_ctx, cred, smb_krb5_context, ktc);
+
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+/* Get server gss credentials (in gsskrb5, this means the keytab) */
+
+int cli_credentials_get_server_gss_creds(struct cli_credentials *cred,
+ struct gssapi_creds_container **_gcc)
+{
+ int ret = 0;
+ OM_uint32 maj_stat, min_stat;
+ struct gssapi_creds_container *gcc;
+ struct keytab_container *ktc;
+ struct smb_krb5_context *smb_krb5_context;
+ TALLOC_CTX *mem_ctx;
+ krb5_principal princ;
+
+ if (cred->server_gss_creds_obtained >= (MAX(cred->keytab_obtained,
+ MAX(cred->principal_obtained,
+ cred->username_obtained)))) {
+ *_gcc = cred->server_gss_creds;
+ return 0;
+ }
+
+ ret = cli_credentials_get_krb5_context(cred, &smb_krb5_context);
+ if (ret) {
+ return ret;
+ }
+
+ ret = cli_credentials_get_keytab(cred,
+ &ktc);
+ if (ret) {
+ DEBUG(1, ("Failed to get keytab for GSSAPI server: %s\n", error_message(ret)));
+ return ret;
+ }
+
+ mem_ctx = talloc_new(cred);
+ if (!mem_ctx) {
+ return ENOMEM;
+ }
+
+ ret = principal_from_credentials(mem_ctx, cred, smb_krb5_context, &princ);
+ if (ret) {
+ DEBUG(1,("cli_credentials_get_server_gss_creds: makeing krb5 principal failed (%s)\n",
+ smb_get_krb5_error_message(smb_krb5_context->krb5_context,
+ ret, mem_ctx)));
+ talloc_free(mem_ctx);
+ return ret;
+ }
+
+ gcc = talloc(cred, struct gssapi_creds_container);
+ if (!gcc) {
+ talloc_free(mem_ctx);
+ return ENOMEM;
+ }
+
+ /* This creates a GSSAPI cred_id_t with the principal and keytab set */
+ maj_stat = gss_krb5_import_cred(&min_stat, NULL, princ, ktc->keytab,
+ &gcc->creds);
+ if (maj_stat) {
+ if (min_stat) {
+ ret = min_stat;
+ } else {
+ ret = EINVAL;
+ }
+ }
+ if (ret == 0) {
+ cred->server_gss_creds_obtained = cred->keytab_obtained;
+ talloc_set_destructor(gcc, free_gssapi_creds);
+ cred->server_gss_creds = gcc;
+ *_gcc = gcc;
+ }
+ talloc_free(mem_ctx);
return ret;
}
@@ -415,3 +598,5 @@ void cli_credentials_set_salt_principal(struct cli_credentials *cred, const char
{
cred->salt_principal = talloc_strdup(cred, principal);
}
+
+