1
0
mirror of https://github.com/samba-team/samba.git synced 2025-02-02 09:47:23 +03:00

r11200: Reposition the creation of the kerberos keytab for GSSAPI and Krb5

authentication.  This pulls the creating of the keytab back to the
credentials code, and removes the special case of 'use keberos keytab
= yes' for now.

This allows (and requires) the callers to specify the credentials for
the server credentails to GENSEC.  This allows kpasswdd (soon to be
added) to use a different set of kerberos credentials.

The 'use kerberos keytab' code will be moved into the credentials
layer, as the layers below now expect a keytab.

We also now allow for the old secret to be stored into the
credentials, allowing service password changes.

Andrew Bartlett
(This used to be commit 205f77c579ac8680c85f713a76de5767189c627b)
This commit is contained in:
Andrew Bartlett 2005-10-20 03:47:55 +00:00 committed by Gerald (Jerry) Carter
parent 9e25f33a1a
commit 372ca26b20
17 changed files with 393 additions and 290 deletions

View File

@ -46,7 +46,12 @@ 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->keytab_obtained = CRED_UNINITIALISED;
cred->principal_obtained = CRED_UNINITIALISED;
cred->old_password = NULL;
cred->smb_krb5_context = NULL;
return cred;
}
@ -209,6 +214,28 @@ BOOL cli_credentials_set_password_callback(struct cli_credentials *cred,
return False;
}
/**
* Obtain the 'old' password for this credentials context (used for join accounts).
* @param cred credentials context
* @retval If set, the cleartext password, otherwise NULL
*/
const char *cli_credentials_get_old_password(struct cli_credentials *cred)
{
if (cred->machine_account_pending) {
cli_credentials_set_machine_account(cred);
}
return cred->old_password;
}
BOOL cli_credentials_set_old_password(struct cli_credentials *cred,
const char *val,
enum credentials_obtained obtained)
{
cred->old_password = talloc_strdup(cred, val);
return True;
}
/**
* Obtain the password for this credentials context.
* @param cred credentials context

View File

@ -48,10 +48,12 @@ struct cli_credentials {
enum credentials_obtained realm_obtained;
enum credentials_obtained ccache_obtained;
enum credentials_obtained principal_obtained;
enum credentials_obtained keytab_obtained;
const char *workstation;
const char *username;
const char *password;
const char *old_password;
const char *domain;
const char *realm;
const char *principal;
@ -59,6 +61,7 @@ struct cli_credentials {
struct samr_Password *nt_hash;
struct ccache_container *ccache;
struct keytab_container *keytab;
const char *(*workstation_cb) (struct cli_credentials *);
const char *(*password_cb) (struct cli_credentials *);
@ -74,6 +77,8 @@ struct cli_credentials {
enum netr_SchannelType secure_channel_type;
int kvno;
struct smb_krb5_context *smb_krb5_context;
/* We are flagged to get machine account details from the
* secrets.ldb when we are asked for a username or password */

View File

@ -164,7 +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
*/
NTSTATUS cli_credentials_set_machine_account(struct cli_credentials *cred)
static NTSTATUS cli_credentials_set_secrets(struct cli_credentials *cred,
const char *base,
const char *filter)
{
TALLOC_CTX *mem_ctx;
@ -184,6 +186,7 @@ NTSTATUS cli_credentials_set_machine_account(struct cli_credentials *cred)
const char *machine_account;
const char *password;
const char *old_password;
const char *domain;
const char *realm;
enum netr_SchannelType sct;
@ -201,10 +204,9 @@ NTSTATUS cli_credentials_set_machine_account(struct cli_credentials *cred)
/* search for the secret record */
ldb_ret = gendb_search(ldb,
mem_ctx, ldb_dn_explode(mem_ctx, SECRETS_PRIMARY_DOMAIN_DN),
mem_ctx, ldb_dn_explode(mem_ctx, base),
&msgs, attrs,
SECRETS_PRIMARY_DOMAIN_FILTER,
cli_credentials_get_domain(cred));
"%s", filter);
if (ldb_ret == 0) {
DEBUG(1, ("Could not find join record to domain: %s\n",
cli_credentials_get_domain(cred)));
@ -218,6 +220,7 @@ NTSTATUS cli_credentials_set_machine_account(struct cli_credentials *cred)
}
password = ldb_msg_find_string(msgs[0], "secret", NULL);
old_password = ldb_msg_find_string(msgs[0], "priorSecret", NULL);
machine_account = ldb_msg_find_string(msgs[0], "samAccountName", NULL);
@ -277,6 +280,52 @@ NTSTATUS cli_credentials_set_machine_account(struct cli_credentials *cred)
return NT_STATUS_OK;
}
/**
* Fill in credentials for the machine trust account, from the secrets database.
*
* @param cred Credentials structure to fill in
* @retval NTSTATUS error detailing any failure
*/
NTSTATUS cli_credentials_set_machine_account(struct cli_credentials *cred)
{
char *filter = talloc_asprintf(cred, SECRETS_PRIMARY_DOMAIN_FILTER,
cli_credentials_get_domain(cred));
return cli_credentials_set_secrets(cred, SECRETS_PRIMARY_DOMAIN_DN,
filter);
}
/**
* Fill in credentials for the machine trust account, from the secrets database.
*
* @param cred Credentials structure to fill in
* @retval NTSTATUS error detailing any failure
*/
NTSTATUS cli_credentials_set_krbtgt(struct cli_credentials *cred)
{
char *filter = talloc_asprintf(cred, SECRETS_KRBTGT_SEARCH,
cli_credentials_get_realm(cred),
cli_credentials_get_domain(cred));
return cli_credentials_set_secrets(cred, SECRETS_PRINCIPALS_DN,
filter);
}
/**
* Fill in credentials for the machine trust account, from the secrets database.
*
* @param cred Credentials structure to fill in
* @retval NTSTATUS error detailing any failure
*/
NTSTATUS cli_credentials_set_stored_principal(struct cli_credentials *cred,
const char *serviceprincipal)
{
char *filter = talloc_asprintf(cred, SECRETS_PRINCIPAL_SEARCH,
cli_credentials_get_realm(cred),
cli_credentials_get_domain(cred),
serviceprincipal);
return cli_credentials_set_secrets(cred, SECRETS_PRINCIPALS_DN,
filter);
}
/**
* Ask that when required, the credentials system will be filled with
* machine trust account, from the secrets database.

View File

@ -26,6 +26,22 @@
#include "system/kerberos.h"
#include "auth/kerberos/kerberos.h"
int cli_credentials_get_krb5_context(struct cli_credentials *cred,
struct smb_krb5_context **smb_krb5_context)
{
int ret;
if (cred->smb_krb5_context) {
*smb_krb5_context = cred->smb_krb5_context;
return 0;
}
ret = smb_krb5_init_context(cred, &cred->smb_krb5_context);
if (ret) {
return ret;
}
*smb_krb5_context = cred->smb_krb5_context;
return 0;
}
int cli_credentials_set_from_ccache(struct cli_credentials *cred,
enum credentials_obtained obtained)
@ -95,11 +111,13 @@ int cli_credentials_set_ccache(struct cli_credentials *cred,
return ENOMEM;
}
ret = smb_krb5_init_context(ccc, &ccc->smb_krb5_context);
ret = cli_credentials_get_krb5_context(cred, &ccc->smb_krb5_context);
if (ret) {
talloc_free(ccc);
return ret;
}
talloc_reference(ccc, ccc->smb_krb5_context);
if (name) {
ret = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context, name, &ccc->ccache);
if (ret) {
@ -170,12 +188,12 @@ int cli_credentials_new_ccache(struct cli_credentials *cred)
return ENOMEM;
}
ret = smb_krb5_init_context(ccc, &ccc->smb_krb5_context);
ret = cli_credentials_get_krb5_context(cred, &ccc->smb_krb5_context);
if (ret) {
talloc_free(ccache_name);
talloc_free(ccc);
return ret;
}
talloc_reference(ccc, ccc->smb_krb5_context);
ret = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context, ccache_name, &ccc->ccache);
if (ret) {
@ -227,6 +245,41 @@ int cli_credentials_get_ccache(struct cli_credentials *cred,
return ret;
}
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;
if (cred->keytab_obtained >= (MAX(cred->principal_obtained,
cred->username_obtained))) {
*_ktc = cred->keytab;
return 0;
}
if (cli_credentials_is_anonymous(cred)) {
return EINVAL;
}
ret = cli_credentials_get_krb5_context(cred, &smb_krb5_context);
if (ret) {
return ret;
}
ret = create_memory_keytab(cred, cred, smb_krb5_context, &ktc);
if (ret) {
return ret;
}
cred->keytab_obtained = (MAX(cred->principal_obtained,
cred->username_obtained));
cred->keytab = ktc;
*_ktc = cred->keytab;
return ret;
}
/**
* Set Kerberos KVNO
*/

View File

@ -439,7 +439,7 @@ const char *gensec_get_name_by_oid(const char *oid_string)
if (ops) {
return ops->name;
}
return NULL;
return oid_string;
}
@ -489,6 +489,22 @@ NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
return gensec_start_mech(gensec_security);
}
/**
* Start a GENSEC sub-mechanism by an internal name
*
*/
NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security,
const char *name)
{
gensec_security->ops = gensec_security_by_name(name);
if (!gensec_security->ops) {
DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
return NT_STATUS_INVALID_PARAMETER;
}
return gensec_start_mech(gensec_security);
}
/*
wrappers for the gensec function pointers
*/

View File

@ -43,7 +43,7 @@ struct gensec_gssapi_state {
struct smb_krb5_context *smb_krb5_context;
krb5_ccache ccache;
const char *ccache_name;
krb5_keytab keytab;
struct keytab_container *keytab;
gss_cred_id_t cred;
};
@ -154,6 +154,7 @@ static NTSTATUS gensec_gssapi_server_start(struct gensec_security *gensec_securi
{
NTSTATUS nt_status;
OM_uint32 maj_stat, min_stat;
int ret;
gss_buffer_desc name_token;
struct gensec_gssapi_state *gensec_gssapi_state;
struct cli_credentials *machine_account;
@ -165,35 +166,30 @@ static NTSTATUS gensec_gssapi_server_start(struct gensec_security *gensec_securi
gensec_gssapi_state = gensec_security->private_data;
machine_account = cli_credentials_init(gensec_gssapi_state);
cli_credentials_set_conf(machine_account);
nt_status = cli_credentials_set_machine_account(machine_account);
machine_account = gensec_get_credentials(gensec_security);
if (!NT_STATUS_IS_OK(nt_status)) {
DEBUG(3, ("Could not obtain machine account credentials from the local database\n"));
talloc_free(machine_account);
return nt_status;
if (!machine_account) {
DEBUG(3, ("No machine account credentials specified\n"));
return NT_STATUS_INVALID_PARAMETER;
} else {
nt_status = create_memory_keytab(gensec_gssapi_state,
machine_account,
gensec_gssapi_state->smb_krb5_context,
&gensec_gssapi_state->keytab);
if (!NT_STATUS_IS_OK(nt_status)) {
ret = cli_credentials_get_keytab(machine_account, &gensec_gssapi_state->keytab);
if (ret) {
DEBUG(3, ("Could not create memory keytab!\n"));
talloc_free(machine_account);
return nt_status;
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
}
}
name_token.value = cli_credentials_get_principal(machine_account,
machine_account);
/* This might have been explicity set to NULL, ie use what the client calls us */
if (name_token.value) {
name_token.length = strlen(name_token.value);
maj_stat = gss_import_name (&min_stat,
&name_token,
GSS_C_NT_USER_NAME,
&gensec_gssapi_state->server_name);
talloc_free(machine_account);
if (maj_stat) {
DEBUG(2, ("GSS Import name of %s failed: %s\n",
@ -201,9 +197,12 @@ static NTSTATUS gensec_gssapi_server_start(struct gensec_security *gensec_securi
gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
return NT_STATUS_UNSUCCESSFUL;
}
} else {
gensec_gssapi_state->server_name = GSS_C_NO_NAME;
}
maj_stat = gsskrb5_acquire_cred(&min_stat,
gensec_gssapi_state->keytab, NULL,
gensec_gssapi_state->keytab->keytab, NULL,
gensec_gssapi_state->server_name,
GSS_C_INDEFINITE,
GSS_C_NULL_OID_SET,

View File

@ -86,6 +86,10 @@ static NTSTATUS gensec_krb5_start(struct gensec_security *gensec_security)
{
struct gensec_krb5_state *gensec_krb5_state;
if (!gensec_get_credentials(gensec_security)) {
return NT_STATUS_INVALID_PARAMETER;
}
gensec_krb5_state = talloc(gensec_security, struct gensec_krb5_state);
if (!gensec_krb5_state) {
return NT_STATUS_NO_MEMORY;
@ -185,7 +189,7 @@ static NTSTATUS gensec_krb5_client_start(struct gensec_security *gensec_security
gensec_krb5_state = gensec_security->private_data;
gensec_krb5_state->state_position = GENSEC_KRB5_CLIENT_START;
ret = cli_credentials_get_ccache(gensec_security->credentials, &ccache_container);
ret = cli_credentials_get_ccache(gensec_get_credentials(gensec_security), &ccache_container);
if (ret) {
DEBUG(1,("gensec_krb5_start: cli_credentials_get_ccache failed: %s\n",
error_message(ret)));
@ -391,7 +395,7 @@ static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security,
nt_status = ads_verify_ticket(out_mem_ctx,
gensec_krb5_state->smb_krb5_context,
&gensec_krb5_state->auth_context,
lp_realm(),
gensec_get_credentials(gensec_security),
gensec_get_target_service(gensec_security), &unwrapped_in,
&gensec_krb5_state->ticket, &unwrapped_out,
&gensec_krb5_state->keyblock);
@ -400,7 +404,7 @@ static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security,
nt_status = ads_verify_ticket(out_mem_ctx,
gensec_krb5_state->smb_krb5_context,
&gensec_krb5_state->auth_context,
lp_realm(),
gensec_get_credentials(gensec_security),
gensec_get_target_service(gensec_security),
&in,
&gensec_krb5_state->ticket, &unwrapped_out,

View File

@ -28,6 +28,12 @@ struct ccache_container {
krb5_ccache ccache;
};
struct keytab_container {
struct smb_krb5_context *smb_krb5_context;
krb5_keytab keytab;
};
/* not really ASN.1, but RFC 1964 */
#define TOK_ID_KRB_AP_REQ "\x01\x00"
#define TOK_ID_KRB_AP_REP "\x02\x00"
@ -81,10 +87,11 @@ krb5_error_code ads_krb5_mk_req(krb5_context context,
krb5_data *outbuf);
DATA_BLOB get_auth_data_from_tkt(TALLOC_CTX *mem_ctx,
krb5_ticket *tkt);
NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx,
NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx,
struct smb_krb5_context *smb_krb5_context,
krb5_auth_context *auth_context,
const char *realm, const char *service,
struct cli_credentials *machine_account,
const char *service,
const DATA_BLOB *enc_ticket,
krb5_ticket **tkt,
DATA_BLOB *ap_rep,
@ -115,10 +122,10 @@ krb5_error_code principal_from_credentials(TALLOC_CTX *parent_ctx,
struct cli_credentials *credentials,
struct smb_krb5_context *smb_krb5_context,
krb5_principal *princ);
NTSTATUS create_memory_keytab(TALLOC_CTX *parent_ctx,
int create_memory_keytab(TALLOC_CTX *parent_ctx,
struct cli_credentials *machine_account,
struct smb_krb5_context *smb_krb5_context,
krb5_keytab *keytab);
struct keytab_container **keytab_container);
NTSTATUS kerberos_decode_pac(TALLOC_CTX *mem_ctx,
struct PAC_DATA **pac_data_out,
DATA_BLOB blob,

View File

@ -33,11 +33,6 @@ struct principal_container {
krb5_principal principal;
};
struct keytab_container {
struct smb_krb5_context *smb_krb5_context;
krb5_keytab keytab;
};
static int free_principal(void *ptr) {
struct principal_container *pc = ptr;
/* current heimdal - 0.6.3, which we need anyway, fixes segfaults here */
@ -111,7 +106,8 @@ krb5_error_code principal_from_credentials(TALLOC_CTX *parent_ctx,
if (!princ_string) {
talloc_free(mem_ctx);
return EINVAL;
princ = NULL;
return 0;
}
ret = krb5_parse_name(smb_krb5_context->krb5_context,
@ -216,36 +212,40 @@ static int free_keytab(void *ptr) {
return 0;
}
NTSTATUS create_memory_keytab(TALLOC_CTX *parent_ctx,
int create_memory_keytab(TALLOC_CTX *parent_ctx,
struct cli_credentials *machine_account,
struct smb_krb5_context *smb_krb5_context,
krb5_keytab *keytab)
struct keytab_container **keytab_container)
{
krb5_error_code ret;
const char *password_s;
char *old_secret;
krb5_data password;
int i;
struct keytab_container *mem_ctx = talloc(parent_ctx, struct keytab_container);
int i, kvno;
krb5_enctype *enctypes;
krb5_principal salt_princ;
krb5_principal princ;
krb5_keytab keytab;
TALLOC_CTX *mem_ctx = talloc_new(parent_ctx);
if (!mem_ctx) {
return NT_STATUS_NO_MEMORY;
return ENOMEM;
}
ret = krb5_kt_resolve(smb_krb5_context->krb5_context, "MEMORY:", keytab);
*keytab_container = talloc(mem_ctx, struct keytab_container);
ret = krb5_kt_resolve(smb_krb5_context->krb5_context, "MEMORY:", &keytab);
if (ret) {
DEBUG(1,("failed to generate a new krb5 keytab: %s\n",
error_message(ret)));
talloc_free(mem_ctx);
return NT_STATUS_INTERNAL_ERROR;
return ret;
}
mem_ctx->smb_krb5_context = talloc_reference(mem_ctx, smb_krb5_context);
mem_ctx->keytab = *keytab;
(*keytab_container)->smb_krb5_context = talloc_reference(*keytab_container, smb_krb5_context);
(*keytab_container)->keytab = keytab;
talloc_set_destructor(mem_ctx, free_keytab);
talloc_set_destructor(*keytab_container, free_keytab);
ret = salt_principal_from_credentials(mem_ctx, machine_account,
smb_krb5_context,
@ -255,7 +255,7 @@ static int free_keytab(void *ptr) {
smb_get_krb5_error_message(smb_krb5_context->krb5_context,
ret, mem_ctx)));
talloc_free(mem_ctx);
return NT_STATUS_INTERNAL_ERROR;
return ret;
}
ret = principal_from_credentials(mem_ctx, machine_account, smb_krb5_context, &princ);
@ -264,10 +264,10 @@ static int free_keytab(void *ptr) {
smb_get_krb5_error_message(smb_krb5_context->krb5_context,
ret, mem_ctx)));
talloc_free(mem_ctx);
return NT_STATUS_INTERNAL_ERROR;
return ret;
}
password_s = talloc_strdup(mem_ctx, cli_credentials_get_password(machine_account));
password_s = cli_credentials_get_password(machine_account);
if (!password_s) {
/* If we don't have the plaintext password, try for
* the MD4 password hash */
@ -279,7 +279,7 @@ static int free_keytab(void *ptr) {
talloc_free(mem_ctx);
DEBUG(1, ("create_memory_keytab: Domain trust informaton for account %s not available\n",
cli_credentials_get_principal(machine_account, mem_ctx)));
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
return EINVAL;
}
ret = krb5_keyblock_init(smb_krb5_context->krb5_context,
ENCTYPE_ARCFOUR_HMAC,
@ -289,12 +289,12 @@ static int free_keytab(void *ptr) {
DEBUG(1, ("create_memory_keytab: krb5_keyblock_init failed: %s\n",
smb_get_krb5_error_message(smb_krb5_context->krb5_context,
ret, mem_ctx)));
return NT_STATUS_INTERNAL_ERROR;
return ret;
}
entry.principal = princ;
entry.vno = cli_credentials_get_kvno(machine_account);
ret = krb5_kt_add_entry(smb_krb5_context->krb5_context, *keytab, &entry);
ret = krb5_kt_add_entry(smb_krb5_context->krb5_context, keytab, &entry);
if (ret) {
DEBUG(1, ("Failed to add ARCFOUR_HMAC (only) entry for %s to keytab: %s",
cli_credentials_get_principal(machine_account, mem_ctx),
@ -302,11 +302,14 @@ static int free_keytab(void *ptr) {
ret, mem_ctx)));
talloc_free(mem_ctx);
krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &entry.keyblock);
return NT_STATUS_INTERNAL_ERROR;
return ret;
}
krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &entry.keyblock);
return NT_STATUS_OK;
talloc_steal(parent_ctx, *keytab_container);
talloc_free(mem_ctx);
return 0;
}
/* good, we actually have the real plaintext */
@ -317,11 +320,12 @@ static int free_keytab(void *ptr) {
DEBUG(1,("create_memory_keytab: getting encrption types failed (%s)\n",
error_message(ret)));
talloc_free(mem_ctx);
return NT_STATUS_INTERNAL_ERROR;
return ret;
}
password.data = discard_const_p(char *, password_s);
password.length = strlen(password_s);
kvno = cli_credentials_get_kvno(machine_account);
for (i=0; enctypes[i]; i++) {
krb5_keytab_entry entry;
@ -329,12 +333,12 @@ static int free_keytab(void *ptr) {
salt_princ, &password, &entry.keyblock, enctypes[i]);
if (ret) {
talloc_free(mem_ctx);
return NT_STATUS_INTERNAL_ERROR;
return ret;
}
entry.principal = princ;
entry.vno = cli_credentials_get_kvno(machine_account);
ret = krb5_kt_add_entry(smb_krb5_context->krb5_context, *keytab, &entry);
entry.vno = kvno;
ret = krb5_kt_add_entry(smb_krb5_context->krb5_context, keytab, &entry);
if (ret) {
DEBUG(1, ("Failed to add entry for %s to keytab: %s",
cli_credentials_get_principal(machine_account, mem_ctx),
@ -342,15 +346,48 @@ static int free_keytab(void *ptr) {
ret, mem_ctx)));
talloc_free(mem_ctx);
krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &entry.keyblock);
return NT_STATUS_INTERNAL_ERROR;
return ret;
}
krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &entry.keyblock);
}
old_secret = cli_credentials_get_old_password(machine_account);
if (kvno != 0 && old_secret) {
password.data = discard_const_p(char *, old_secret);
password.length = strlen(old_secret);
for (i=0; enctypes[i]; i++) {
krb5_keytab_entry entry;
ret = create_kerberos_key_from_string(smb_krb5_context->krb5_context,
salt_princ, &password, &entry.keyblock, enctypes[i]);
if (ret) {
talloc_free(mem_ctx);
return ret;
}
entry.principal = princ;
entry.vno = kvno - 1;
ret = krb5_kt_add_entry(smb_krb5_context->krb5_context, keytab, &entry);
if (ret) {
DEBUG(1, ("Failed to add 'old password' entry for %s to keytab: %s",
cli_credentials_get_principal(machine_account, mem_ctx),
smb_get_krb5_error_message(smb_krb5_context->krb5_context,
ret, mem_ctx)));
talloc_free(mem_ctx);
krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &entry.keyblock);
return ret;
}
krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &entry.keyblock);
}
}
free_kerberos_etypes(smb_krb5_context->krb5_context, enctypes);
return NT_STATUS_OK;
talloc_steal(parent_ctx, *keytab_container);
talloc_free(mem_ctx);
return 0;
}

View File

@ -63,156 +63,6 @@ DATA_BLOB unwrap_pac(TALLOC_CTX *mem_ctx, DATA_BLOB *auth_data)
return out;
}
/**********************************************************************************
Try to verify a ticket using the system keytab... the system keytab has kvno -1 entries, so
it's more like what microsoft does... see comment in utils/net_ads.c in the
ads_keytab_add_entry function for details.
***********************************************************************************/
static krb5_error_code ads_keytab_verify_ticket(TALLOC_CTX *mem_ctx, krb5_context context,
krb5_auth_context *auth_context,
const char *service,
const krb5_data *p_packet,
krb5_flags *ap_req_options,
krb5_ticket **pp_tkt,
krb5_keyblock **keyblock)
{
krb5_error_code ret = 0;
krb5_keytab keytab = NULL;
krb5_kt_cursor kt_cursor;
krb5_keytab_entry kt_entry;
char *valid_princ_formats[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
char *entry_princ_s = NULL;
const char *my_name, *my_fqdn;
int i;
int number_matched_principals = 0;
const char *last_error_message;
/* Generate the list of principal names which we expect
* clients might want to use for authenticating to the file
* service. We allow name$,{host,service}/{name,fqdn,name.REALM}.
* (where service is specified by the caller) */
my_name = lp_netbios_name();
my_fqdn = name_to_fqdn(mem_ctx, my_name);
asprintf(&valid_princ_formats[0], "%s$@%s", my_name, lp_realm());
asprintf(&valid_princ_formats[1], "host/%s@%s", my_name, lp_realm());
asprintf(&valid_princ_formats[2], "host/%s@%s", my_fqdn, lp_realm());
asprintf(&valid_princ_formats[3], "host/%s.%s@%s", my_name, lp_realm(), lp_realm());
asprintf(&valid_princ_formats[4], "%s/%s@%s", service, my_name, lp_realm());
asprintf(&valid_princ_formats[5], "%s/%s@%s", service, my_fqdn, lp_realm());
asprintf(&valid_princ_formats[6], "%s/%s.%s@%s", service, my_name, lp_realm(), lp_realm());
ZERO_STRUCT(kt_entry);
ZERO_STRUCT(kt_cursor);
ret = krb5_kt_default(context, &keytab);
if (ret) {
last_error_message = smb_get_krb5_error_message(context, ret, mem_ctx);
DEBUG(1, ("ads_keytab_verify_ticket: krb5_kt_default failed (%s)\n",
last_error_message));
goto out;
}
/* Iterate through the keytab. For each key, if the principal
* name case-insensitively matches one of the allowed formats,
* try verifying the ticket using that principal. */
ret = krb5_kt_start_seq_get(context, keytab, &kt_cursor);
if (ret == KRB5_KT_END || ret == ENOENT ) {
last_error_message = smb_get_krb5_error_message(context, ret, mem_ctx);
} else if (ret) {
last_error_message = smb_get_krb5_error_message(context, ret, mem_ctx);
DEBUG(1, ("ads_keytab_verify_ticket: krb5_kt_start_seq_get failed (%s)\n",
last_error_message));
} else {
ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; /* Pick an error... */
last_error_message = "No principals in Keytab";
while (ret && (krb5_kt_next_entry(context, keytab, &kt_entry, &kt_cursor) == 0)) {
krb5_error_code upn_ret;
upn_ret = krb5_unparse_name(context, kt_entry.principal, &entry_princ_s);
if (upn_ret) {
last_error_message = smb_get_krb5_error_message(context, ret, mem_ctx);
DEBUG(1, ("ads_keytab_verify_ticket: krb5_unparse_name failed (%s)\n",
last_error_message));
ret = upn_ret;
break;
}
for (i = 0; i < ARRAY_SIZE(valid_princ_formats); i++) {
if (!strequal(entry_princ_s, valid_princ_formats[i])) {
continue;
}
number_matched_principals++;
*pp_tkt = NULL;
ret = krb5_rd_req_return_keyblock(context, auth_context, p_packet,
kt_entry.principal, keytab,
ap_req_options, pp_tkt, keyblock);
if (ret) {
last_error_message = smb_get_krb5_error_message(context, ret, mem_ctx);
DEBUG(10, ("ads_keytab_verify_ticket: krb5_rd_req(%s) failed: %s\n",
entry_princ_s, last_error_message));
} else {
DEBUG(3,("ads_keytab_verify_ticket: krb5_rd_req succeeded for principal %s\n",
entry_princ_s));
break;
}
}
/* Free the name we parsed. */
krb5_free_unparsed_name(context, entry_princ_s);
entry_princ_s = NULL;
/* Free the entry we just read. */
smb_krb5_kt_free_entry(context, &kt_entry);
ZERO_STRUCT(kt_entry);
}
krb5_kt_end_seq_get(context, keytab, &kt_cursor);
}
ZERO_STRUCT(kt_cursor);
out:
if (ret) {
if (!number_matched_principals) {
DEBUG(3, ("ads_keytab_verify_ticket: no keytab principals matched expected file service name.\n"));
} else {
DEBUG(3, ("ads_keytab_verify_ticket: krb5_rd_req failed for all %d matched keytab principals\n",
number_matched_principals));
}
DEBUG(3, ("ads_keytab_verify_ticket: last error: %s\n", last_error_message));
}
if (entry_princ_s) {
krb5_free_unparsed_name(context, entry_princ_s);
}
{
krb5_keytab_entry zero_kt_entry;
ZERO_STRUCT(zero_kt_entry);
if (memcmp(&zero_kt_entry, &kt_entry, sizeof(krb5_keytab_entry))) {
smb_krb5_kt_free_entry(context, &kt_entry);
}
}
{
krb5_kt_cursor zero_csr;
ZERO_STRUCT(zero_csr);
if ((memcmp(&kt_cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && keytab) {
krb5_kt_end_seq_get(context, keytab, &kt_cursor);
}
}
if (keytab) {
krb5_kt_close(context, keytab);
}
return ret;
}
/**********************************************************************************
Verify an incoming ticket and parse out the principal name and
authorization_data if available.
@ -221,7 +71,8 @@ static krb5_error_code ads_keytab_verify_ticket(TALLOC_CTX *mem_ctx, krb5_contex
NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx,
struct smb_krb5_context *smb_krb5_context,
krb5_auth_context *auth_context,
const char *realm, const char *service,
struct cli_credentials *machine_account,
const char *service,
const DATA_BLOB *enc_ticket,
krb5_ticket **tkt,
DATA_BLOB *ap_rep,
@ -229,31 +80,11 @@ static krb5_error_code ads_keytab_verify_ticket(TALLOC_CTX *mem_ctx, krb5_contex
{
krb5_keyblock *local_keyblock;
krb5_data packet;
krb5_principal salt_princ;
int ret;
krb5_flags ap_req_options = 0;
krb5_principal server;
NTSTATUS creds_nt_status, status;
struct cli_credentials *machine_account;
machine_account = cli_credentials_init(mem_ctx);
cli_credentials_set_conf(machine_account);
creds_nt_status = cli_credentials_set_machine_account(machine_account);
if (!NT_STATUS_IS_OK(creds_nt_status)) {
DEBUG(3, ("Could not obtain machine account credentials from the local database\n"));
talloc_free(machine_account);
machine_account = NULL;
} else {
ret = salt_principal_from_credentials(mem_ctx, machine_account,
smb_krb5_context,
&salt_princ);
if (ret) {
DEBUG(1,("ads_verify_ticket: maksing salt principal failed (%s)\n",
error_message(ret)));
return NT_STATUS_INTERNAL_ERROR;
}
}
struct keytab_container *keytab_container;
/* This whole process is far more complex than I would
like. We have to go through all this to allow us to store
@ -268,25 +99,19 @@ static krb5_error_code ads_keytab_verify_ticket(TALLOC_CTX *mem_ctx, krb5_contex
packet.length = enc_ticket->length;
packet.data = (krb5_pointer)enc_ticket->data;
ret = ads_keytab_verify_ticket(mem_ctx, smb_krb5_context->krb5_context, auth_context,
service, &packet, &ap_req_options, tkt, &local_keyblock);
if (ret && machine_account) {
krb5_keytab keytab;
krb5_principal server;
status = create_memory_keytab(mem_ctx, machine_account, smb_krb5_context,
&keytab);
if (!NT_STATUS_IS_OK(status)) {
return status;
ret = cli_credentials_get_keytab(machine_account, &keytab_container);
if (ret) {
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
}
ret = principal_from_credentials(mem_ctx, machine_account, smb_krb5_context,
&server);
if (ret == 0) {
ret = krb5_rd_req_return_keyblock(smb_krb5_context->krb5_context, auth_context, &packet,
server,
keytab, &ap_req_options, tkt,
keytab_container->keytab, &ap_req_options, tkt,
&local_keyblock);
}
}
if (ret) {
DEBUG(3,("ads_secrets_verify_ticket: failed to decrypt with error %s\n",

View File

@ -63,6 +63,7 @@ static NTSTATUS ldapsrv_BindSASL(struct ldapsrv_call *call)
DEBUG(10, ("BindSASL dn: %s\n",req->dn));
if (!call->conn->gensec) {
struct cli_credentials *server_credentials;
call->conn->session_info = NULL;
status = gensec_server_start(call->conn, &call->conn->gensec,
@ -74,6 +75,23 @@ static NTSTATUS ldapsrv_BindSASL(struct ldapsrv_call *call)
gensec_set_target_service(call->conn->gensec, "ldap");
server_credentials
= cli_credentials_init(call);
if (!server_credentials) {
DEBUG(1, ("Failed to init server credentials\n"));
return NT_STATUS_NO_MEMORY;
}
cli_credentials_set_conf(server_credentials);
status = cli_credentials_set_machine_account(server_credentials);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10, ("Failed to obtain server credentials, perhaps a standalone server?: %s\n", nt_errstr(status)));
talloc_free(server_credentials);
server_credentials = NULL;
}
gensec_set_credentials(call->conn->gensec, server_credentials);
gensec_want_feature(call->conn->gensec, GENSEC_FEATURE_SIGN);
gensec_want_feature(call->conn->gensec, GENSEC_FEATURE_SEAL);
gensec_want_feature(call->conn->gensec, GENSEC_FEATURE_ASYNC_REPLIES);

View File

@ -32,6 +32,7 @@
*/
BOOL dcesrv_auth_bind(struct dcesrv_call_state *call)
{
struct cli_credentials *server_credentials;
struct ncacn_packet *pkt = &call->pkt;
struct dcesrv_connection *dce_conn = call->conn;
struct dcesrv_auth *auth = &dce_conn->auth_state;
@ -61,6 +62,23 @@ BOOL dcesrv_auth_bind(struct dcesrv_call_state *call)
return False;
}
server_credentials
= cli_credentials_init(call);
if (!server_credentials) {
DEBUG(1, ("Failed to init server credentials\n"));
return False;
}
cli_credentials_set_conf(server_credentials);
status = cli_credentials_set_machine_account(server_credentials);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10, ("Failed to obtain server credentials, perhaps a standalone server?: %s\n", nt_errstr(status)));
talloc_free(server_credentials);
server_credentials = NULL;
}
gensec_set_credentials(auth->gensec_security, server_credentials);
status = gensec_start_mech_by_authtype(auth->gensec_security, auth->auth_info->auth_type,
auth->auth_info->auth_level);

View File

@ -35,3 +35,16 @@ whenCreated: ${LDAPTIME}
whenChanged: ${LDAPTIME}
msDS-KeyVersionNumber: 1
objectSid: ${DOMAINSID}
dn: samAccountName=krbtgt,flatname=${DOMAIN},CN=Principals
objectClass: top
objectClass: secret
flatname: ${DOMAIN}
realm: ${REALM}
secret: ${KRBTGTPASS}
sAMAccountName: krbtgt
whenCreated: ${LDAPTIME}
whenChanged: ${LDAPTIME}
msDS-KeyVersionNumber: 1
objectSid: ${DOMAINSID}
servicePrincipalName: kadmin/changepw

View File

@ -326,6 +326,7 @@ static void reply_nt1(struct smbsrv_request *req, uint16_t choice)
req_push_str(req, NULL, lp_netbios_name(), -1, STR_UNICODE|STR_TERMINATE|STR_NOALIGN);
DEBUG(3,("not using SPNEGO\n"));
} else {
struct cli_credentials *server_credentials;
struct gensec_security *gensec_security;
DATA_BLOB null_data_blob = data_blob(NULL, 0);
DATA_BLOB blob;
@ -333,19 +334,38 @@ static void reply_nt1(struct smbsrv_request *req, uint16_t choice)
&gensec_security,
req->smb_conn->connection->event.ctx);
if (req->smb_conn->negotiate.auth_context) {
smbsrv_terminate_connection(req->smb_conn, "reply_nt1: is this a secondary negprot? auth_context is non-NULL!\n");
return;
}
req->smb_conn->negotiate.auth_context = NULL;
if (!NT_STATUS_IS_OK(nt_status)) {
DEBUG(0, ("Failed to start GENSEC: %s\n", nt_errstr(nt_status)));
smbsrv_terminate_connection(req->smb_conn, "Failed to start GENSEC\n");
return;
}
if (req->smb_conn->negotiate.auth_context) {
smbsrv_terminate_connection(req->smb_conn, "reply_nt1: is this a secondary negprot? auth_context is non-NULL!\n");
return;
}
server_credentials
= cli_credentials_init(req);
if (!server_credentials) {
smbsrv_terminate_connection(req->smb_conn, "Failed to init server credentials\n");
return;
}
cli_credentials_set_conf(server_credentials);
nt_status = cli_credentials_set_machine_account(server_credentials);
if (!NT_STATUS_IS_OK(nt_status)) {
DEBUG(10, ("Failed to obtain server credentials, perhaps a standalone server?: %s\n", nt_errstr(nt_status)));
talloc_free(server_credentials);
server_credentials = NULL;
}
req->smb_conn->negotiate.server_credentials = talloc_steal(req->smb_conn, server_credentials);
gensec_set_target_service(gensec_security, "cifs");
gensec_set_credentials(gensec_security, server_credentials);
nt_status = gensec_start_mech_by_oid(gensec_security, GENSEC_OID_SPNEGO);
if (!NT_STATUS_IS_OK(nt_status)) {

View File

@ -293,6 +293,8 @@ static NTSTATUS sesssetup_spnego(struct smbsrv_request *req, union smb_sesssetup
return status;
}
gensec_set_credentials(gensec_ctx, req->smb_conn->negotiate.server_credentials);
gensec_set_target_service(gensec_ctx, "cifs");
gensec_want_feature(gensec_ctx, GENSEC_FEATURE_SESSION_KEY);

View File

@ -194,8 +194,8 @@ struct smbsrv_connection {
/* authentication context for multi-part negprot */
struct auth_context *auth_context;
/* state of NTLMSSP auth */
struct auth_ntlmssp_state *ntlmssp_state;
/* reference to the kerberos keytab, or machine trust account */
struct cli_credentials *server_credentials;
/* did we tell the client we support encrypted passwords? */
BOOL encrypted_passwords;

View File

@ -392,6 +392,16 @@ static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
if (opt_workstation) {
cli_credentials_set_workstation(creds, opt_workstation, CRED_SPECIFIED);
}
switch (stdio_helper_mode) {
case GSS_SPNEGO_SERVER:
case SQUID_2_5_NTLMSSP:
cli_credentials_set_machine_account(creds);
break;
default:
break;
}
gensec_set_credentials(state->gensec_state, creds);
switch (stdio_helper_mode) {