mirror of
https://github.com/samba-team/samba.git
synced 2025-02-23 09:57:40 +03:00
Add two new parameters to control how we verify kerberos tickets. Removes lp_use_kerberos_keytab parameter.
The first is "kerberos method" and replaces the "use kerberos keytab" with an enum. Valid options are: secrets only - use only the secrets for ticket verification (default) system keytab - use only the system keytab for ticket verification dedicated keytab - use a dedicated keytab for ticket verification. secrets and keytab - use the secrets.tdb first, then the system keytab For existing installs: "use kerberos keytab = yes" corresponds to secrets and keytab "use kerberos keytab = no" corresponds to secrets only The major difference between "system keytab" and "dedicated keytab" is that the latter method relies on kerberos to find the correct keytab entry instead of filtering based on expected principals. The second parameter is "dedicated keytab file", which is the keytab to use when in "dedicated keytab" mode. This keytab is only used in ads_verify_ticket.
This commit is contained in:
parent
d75b3913c9
commit
d96248a9b4
@ -879,8 +879,25 @@ char *talloc_asprintf_strupper_m(TALLOC_CTX *t, const char *fmt, ...) PRINTF_ATT
|
||||
#define XATTR_REPLACE 0x2 /* set value, fail if attr does not exist */
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_KRB5)
|
||||
/*
|
||||
* This should be under the HAVE_KRB5 flag but since they're used
|
||||
* in lp_kerberos_method(), they ned to be always available
|
||||
*/
|
||||
#define KERBEROS_VERIFY_SECRETS 0
|
||||
#define KERBEROS_VERIFY_SYSTEM_KEYTAB 1
|
||||
#define KERBEROS_VERIFY_DEDICATED_KEYTAB 2
|
||||
#define KERBEROS_VERIFY_SECRETS_AND_KEYTAB 3
|
||||
|
||||
/*
|
||||
* If you add any entries to the above, please modify the below expressions
|
||||
* so they remain accurate.
|
||||
*/
|
||||
#define USE_KERBEROS_KEYTAB (KERBEROS_VERIFY_SECRETS != lp_kerberos_method())
|
||||
#define USE_SYSTEM_KEYTAB \
|
||||
((KERBEROS_VERIFY_SECRETS_AND_KEYTAB == lp_kerberos_method()) || \
|
||||
(KERBEROS_VERIFY_SYSTEM_KEYTAB == lp_kerberos_method()))
|
||||
|
||||
#if defined(HAVE_KRB5)
|
||||
krb5_error_code smb_krb5_parse_name(krb5_context context,
|
||||
const char *name, /* in unix charset */
|
||||
krb5_principal *principal);
|
||||
|
@ -4060,7 +4060,8 @@ bool lp_client_use_spnego(void);
|
||||
bool lp_hostname_lookups(void);
|
||||
bool lp_change_notify(const struct share_params *p );
|
||||
bool lp_kernel_change_notify(const struct share_params *p );
|
||||
bool lp_use_kerberos_keytab(void);
|
||||
char * lp_dedicated_keytab_file(void);
|
||||
int lp_kerberos_method(void);
|
||||
bool lp_defer_sharing_violations(void);
|
||||
bool lp_enable_privileges(void);
|
||||
bool lp_enable_asu_support(void);
|
||||
|
@ -31,6 +31,86 @@
|
||||
const krb5_data *krb5_princ_component(krb5_context, krb5_principal, int );
|
||||
#endif
|
||||
|
||||
static bool ads_dedicated_keytab_verify_ticket(krb5_context context,
|
||||
krb5_auth_context auth_context,
|
||||
const DATA_BLOB *ticket,
|
||||
krb5_ticket **pp_tkt,
|
||||
krb5_keyblock **keyblock,
|
||||
krb5_error_code *perr)
|
||||
{
|
||||
krb5_error_code ret = 0;
|
||||
bool auth_ok = false;
|
||||
krb5_keytab keytab = NULL;
|
||||
krb5_keytab_entry kt_entry;
|
||||
krb5_ticket *dec_ticket = NULL;
|
||||
|
||||
krb5_data packet;
|
||||
|
||||
*pp_tkt = NULL;
|
||||
*keyblock = NULL;
|
||||
*perr = 0;
|
||||
|
||||
ZERO_STRUCT(kt_entry);
|
||||
|
||||
ret = smb_krb5_open_keytab(context, lp_dedicated_keytab_file(), true,
|
||||
&keytab);
|
||||
if (ret) {
|
||||
DEBUG(1, ("smb_krb5_open_keytab failed (%s)\n",
|
||||
error_message(ret)));
|
||||
goto out;
|
||||
}
|
||||
|
||||
packet.length = ticket->length;
|
||||
packet.data = (char *)ticket->data;
|
||||
*pp_tkt = NULL;
|
||||
|
||||
ret = krb5_rd_req(context, &auth_context, &packet, NULL, keytab,
|
||||
NULL, &dec_ticket);
|
||||
if (ret) {
|
||||
DEBUG(0, ("krb5_rd_req failed (%s)\n", error_message(ret)));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Get the key for checking the pac signature */
|
||||
ret = krb5_kt_get_entry(context, keytab, dec_ticket->server,
|
||||
dec_ticket->enc_part.kvno, dec_ticket->enc_part.enctype,
|
||||
&kt_entry);
|
||||
if (ret) {
|
||||
DEBUG(0, ("krb5_kt_get_entry failed (%s)\n",
|
||||
error_message(ret)));
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK /* Heimdal */
|
||||
ret = krb5_copy_keyblock(context, &kt_entry.keyblock, keyblock);
|
||||
#elif defined(HAVE_KRB5_KEYTAB_ENTRY_KEY) /* MIT */
|
||||
ret = krb5_copy_keyblock(context, &kt_entry.key, keyblock);
|
||||
#else
|
||||
#error UNKNOWN_KRB5_KEYTAB_ENTRY_FORMAT
|
||||
#endif
|
||||
smb_krb5_kt_free_entry(context, &kt_entry);
|
||||
|
||||
if (ret) {
|
||||
DEBUG(0, ("failed to copy key: %s\n",
|
||||
error_message(ret)));
|
||||
goto out;
|
||||
}
|
||||
|
||||
auth_ok = true;
|
||||
*pp_tkt = dec_ticket;
|
||||
dec_ticket = NULL;
|
||||
|
||||
out:
|
||||
if (dec_ticket)
|
||||
krb5_free_ticket(context, dec_ticket);
|
||||
|
||||
if (keytab)
|
||||
krb5_kt_close(context, keytab);
|
||||
|
||||
*perr = ret;
|
||||
return auth_ok;
|
||||
}
|
||||
|
||||
/**********************************************************************************
|
||||
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
|
||||
@ -437,22 +517,38 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx,
|
||||
}
|
||||
}
|
||||
|
||||
/* Try secrets.tdb first and fallback to the krb5.keytab if
|
||||
necessary */
|
||||
switch (lp_kerberos_method()) {
|
||||
default:
|
||||
case KERBEROS_VERIFY_SECRETS:
|
||||
auth_ok = ads_secrets_verify_ticket(context, auth_context,
|
||||
host_princ, ticket, &tkt, &keyblock, &ret);
|
||||
break;
|
||||
case KERBEROS_VERIFY_SYSTEM_KEYTAB:
|
||||
auth_ok = ads_keytab_verify_ticket(context, auth_context,
|
||||
ticket, &tkt, &keyblock, &ret);
|
||||
break;
|
||||
case KERBEROS_VERIFY_DEDICATED_KEYTAB:
|
||||
auth_ok = ads_dedicated_keytab_verify_ticket(context,
|
||||
auth_context, ticket, &tkt, &keyblock, &ret);
|
||||
break;
|
||||
case KERBEROS_VERIFY_SECRETS_AND_KEYTAB:
|
||||
/* First try secrets.tdb and fallback to the krb5.keytab if
|
||||
necessary. This is the pre 3.4 behavior when
|
||||
"use kerberos keytab" was true.*/
|
||||
auth_ok = ads_secrets_verify_ticket(context, auth_context,
|
||||
host_princ, ticket, &tkt, &keyblock, &ret);
|
||||
|
||||
auth_ok = ads_secrets_verify_ticket(context, auth_context, host_princ,
|
||||
ticket, &tkt, &keyblock, &ret);
|
||||
|
||||
if (!auth_ok &&
|
||||
(ret == KRB5KRB_AP_ERR_TKT_NYV ||
|
||||
ret == KRB5KRB_AP_ERR_TKT_EXPIRED ||
|
||||
ret == KRB5KRB_AP_ERR_SKEW)) {
|
||||
goto auth_failed;
|
||||
}
|
||||
|
||||
if (!auth_ok && lp_use_kerberos_keytab()) {
|
||||
auth_ok = ads_keytab_verify_ticket(context, auth_context,
|
||||
ticket, &tkt, &keyblock, &ret);
|
||||
if (!auth_ok) {
|
||||
/* Only fallback if we failed to decrypt the ticket */
|
||||
if (ret != KRB5KRB_AP_ERR_TKT_NYV &&
|
||||
ret != KRB5KRB_AP_ERR_TKT_EXPIRED &&
|
||||
ret != KRB5KRB_AP_ERR_SKEW) {
|
||||
auth_ok = ads_keytab_verify_ticket(context,
|
||||
auth_context, ticket, &tkt, &keyblock,
|
||||
&ret);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ( use_replay_cache ) {
|
||||
@ -465,7 +561,6 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx,
|
||||
#endif
|
||||
}
|
||||
|
||||
auth_failed:
|
||||
if (!auth_ok) {
|
||||
DEBUG(3,("ads_verify_ticket: krb5_rd_req with auth failed (%s)\n",
|
||||
error_message(ret)));
|
||||
|
@ -504,7 +504,7 @@ static ADS_STATUS libnet_join_set_os_attributes(TALLOC_CTX *mem_ctx,
|
||||
static bool libnet_join_create_keytab(TALLOC_CTX *mem_ctx,
|
||||
struct libnet_JoinCtx *r)
|
||||
{
|
||||
if (!lp_use_kerberos_keytab()) {
|
||||
if (!USE_SYSTEM_KEYTAB) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -322,7 +322,8 @@ struct global {
|
||||
bool bHostnameLookups;
|
||||
bool bUnixExtensions;
|
||||
bool bDisableNetbios;
|
||||
bool bUseKerberosKeytab;
|
||||
char * szDedicatedKeytabFile;
|
||||
int iKerberosMethod;
|
||||
bool bDeferSharingViolations;
|
||||
bool bEnablePrivileges;
|
||||
bool bASUSupport;
|
||||
@ -861,6 +862,17 @@ static const struct enum_list enum_config_backend[] = {
|
||||
{-1, NULL}
|
||||
};
|
||||
|
||||
/* ADS kerberos ticket verification options */
|
||||
|
||||
static const struct enum_list enum_kerberos_method[] = {
|
||||
{KERBEROS_VERIFY_SECRETS, "default"},
|
||||
{KERBEROS_VERIFY_SECRETS, "secrets only"},
|
||||
{KERBEROS_VERIFY_SYSTEM_KEYTAB, "system keytab"},
|
||||
{KERBEROS_VERIFY_DEDICATED_KEYTAB, "dedicated keytab"},
|
||||
{KERBEROS_VERIFY_SECRETS_AND_KEYTAB, "secrets and keytab"},
|
||||
{-1, NULL}
|
||||
};
|
||||
|
||||
/* Note: We do not initialise the defaults union - it is not allowed in ANSI C
|
||||
*
|
||||
* The FLAG_HIDE is explicit. Paramters set this way do NOT appear in any edit
|
||||
@ -1745,14 +1757,24 @@ static struct parm_struct parm_table[] = {
|
||||
.flags = FLAG_ADVANCED | FLAG_GLOBAL,
|
||||
},
|
||||
{
|
||||
.label = "use kerberos keytab",
|
||||
.type = P_BOOL,
|
||||
.label = "dedicated keytab file",
|
||||
.type = P_STRING,
|
||||
.p_class = P_GLOBAL,
|
||||
.ptr = &Globals.bUseKerberosKeytab,
|
||||
.ptr = &Globals.szDedicatedKeytabFile,
|
||||
.special = NULL,
|
||||
.enum_list = NULL,
|
||||
.flags = FLAG_ADVANCED,
|
||||
},
|
||||
{
|
||||
.label = "kerberos method",
|
||||
.type = P_ENUM,
|
||||
.p_class = P_GLOBAL,
|
||||
.ptr = &Globals.iKerberosMethod,
|
||||
.special = NULL,
|
||||
.enum_list = enum_kerberos_method,
|
||||
.flags = FLAG_ADVANCED,
|
||||
},
|
||||
|
||||
|
||||
{N_("Logging Options"), P_SEP, P_SEPARATOR},
|
||||
|
||||
@ -5322,7 +5344,8 @@ FN_GLOBAL_BOOL(lp_client_use_spnego, &Globals.bClientUseSpnego)
|
||||
FN_GLOBAL_BOOL(lp_hostname_lookups, &Globals.bHostnameLookups)
|
||||
FN_LOCAL_PARM_BOOL(lp_change_notify, bChangeNotify)
|
||||
FN_LOCAL_PARM_BOOL(lp_kernel_change_notify, bKernelChangeNotify)
|
||||
FN_GLOBAL_BOOL(lp_use_kerberos_keytab, &Globals.bUseKerberosKeytab)
|
||||
FN_GLOBAL_STRING(lp_dedicated_keytab_file, &Globals.szDedicatedKeytabFile)
|
||||
FN_GLOBAL_INTEGER(lp_kerberos_method, &Globals.iKerberosMethod)
|
||||
FN_GLOBAL_BOOL(lp_defer_sharing_violations, &Globals.bDeferSharingViolations)
|
||||
FN_GLOBAL_BOOL(lp_enable_privileges, &Globals.bEnablePrivileges)
|
||||
FN_GLOBAL_BOOL(lp_enable_asu_support, &Globals.bASUSupport)
|
||||
|
@ -1147,7 +1147,7 @@ static bool pipe_spnego_auth_bind_negotiate(pipes_struct *p, prs_struct *rpc_in_
|
||||
}
|
||||
DEBUG(3,("pipe_spnego_auth_bind_negotiate: Got secblob of size %lu\n", (unsigned long)secblob.length));
|
||||
|
||||
if ( got_kerberos_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) {
|
||||
if ( got_kerberos_mechanism && ((lp_security()==SEC_ADS) || USE_KERBEROS_KEYTAB) ) {
|
||||
bool ret = pipe_spnego_auth_bind_kerberos(p, rpc_in_p, pauth_info, &secblob, pout_auth);
|
||||
data_blob_free(&secblob);
|
||||
data_blob_free(&blob);
|
||||
|
@ -212,7 +212,7 @@ static DATA_BLOB negprot_spnego(void)
|
||||
|
||||
*/
|
||||
|
||||
if (lp_security() != SEC_ADS && !lp_use_kerberos_keytab()) {
|
||||
if (lp_security() != SEC_ADS && !USE_KERBEROS_KEYTAB) {
|
||||
#if 0
|
||||
/* Code for PocketPC client */
|
||||
blob = data_blob(guid, 16);
|
||||
|
@ -795,7 +795,7 @@ static void reply_spnego_negotiate(struct smb_request *req,
|
||||
|
||||
#ifdef HAVE_KRB5
|
||||
if (kerb_mech && ((lp_security()==SEC_ADS) ||
|
||||
lp_use_kerberos_keytab()) ) {
|
||||
USE_KERBEROS_KEYTAB) ) {
|
||||
bool destroy_vuid = True;
|
||||
reply_spnego_kerberos(req, &secblob, kerb_mech,
|
||||
vuid, &destroy_vuid);
|
||||
@ -887,7 +887,7 @@ static void reply_spnego_auth(struct smb_request *req,
|
||||
(unsigned long)secblob.length));
|
||||
#ifdef HAVE_KRB5
|
||||
if (kerb_mech && ((lp_security()==SEC_ADS) ||
|
||||
lp_use_kerberos_keytab()) ) {
|
||||
USE_KERBEROS_KEYTAB)) {
|
||||
bool destroy_vuid = True;
|
||||
reply_spnego_kerberos(req, &secblob, kerb_mech,
|
||||
vuid, &destroy_vuid);
|
||||
|
@ -1920,7 +1920,7 @@ int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
|
||||
|
||||
d_printf("Password change for principal %s succeeded.\n", host_principal);
|
||||
|
||||
if (lp_use_kerberos_keytab()) {
|
||||
if (USE_SYSTEM_KEYTAB) {
|
||||
d_printf("Attempting to update system keytab with new password.\n");
|
||||
if (ads_keytab_create_default(ads)) {
|
||||
d_printf("Failed to update system keytab.\n");
|
||||
@ -2241,9 +2241,9 @@ int net_ads_keytab(struct net_context *c, int argc, const char **argv)
|
||||
{NULL, NULL, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
if (!lp_use_kerberos_keytab()) {
|
||||
d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
|
||||
use keytab functions.\n");
|
||||
if (!USE_KERBEROS_KEYTAB) {
|
||||
d_printf("\nWarning: \"kerberos method\" must be set to a \
|
||||
keytab method to use keytab functions.\n");
|
||||
}
|
||||
|
||||
return net_run_function(c, argc, argv, "net ads keytab", func);
|
||||
|
@ -1360,7 +1360,7 @@ static bool fork_domain_child(struct winbindd_child *child)
|
||||
}
|
||||
|
||||
if (child->domain && child->domain->primary &&
|
||||
!lp_use_kerberos_keytab() &&
|
||||
!USE_KERBEROS_KEYTAB &&
|
||||
lp_server_role() == ROLE_DOMAIN_MEMBER) {
|
||||
|
||||
struct timeval next_change;
|
||||
|
Loading…
x
Reference in New Issue
Block a user