The branch, master has been updated via d96248a9b46559552f53b0ecd3861387ea7ff050 (commit) from d75b3913c9e03ff97336aa7a6e1cbac2eb03f230 (commit)
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit d96248a9b46559552f53b0ecd3861387ea7ff050 Author: Dan Sledz <dsl...@isilon.com> Date: Thu Jan 15 17:02:41 2009 -0800 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. ----------------------------------------------------------------------- Summary of changes: source3/include/includes.h | 19 +++++- source3/include/proto.h | 3 +- source3/libads/kerberos_verify.c | 129 +++++++++++++++++++++++++++++++++----- source3/libnet/libnet_join.c | 2 +- source3/param/loadparm.c | 33 ++++++++-- source3/rpc_server/srv_pipe.c | 2 +- source3/smbd/negprot.c | 2 +- source3/smbd/sesssetup.c | 4 +- source3/utils/net_ads.c | 8 +- source3/winbindd/winbindd_dual.c | 2 +- 10 files changed, 170 insertions(+), 34 deletions(-) Changeset truncated at 500 lines: diff --git a/source3/include/includes.h b/source3/include/includes.h index c58ebcd..ebd8923 100644 --- a/source3/include/includes.h +++ b/source3/include/includes.h @@ -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); diff --git a/source3/include/proto.h b/source3/include/proto.h index c97adaa..285b44d 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -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); diff --git a/source3/libads/kerberos_verify.c b/source3/libads/kerberos_verify.c index de3fdeb..4483d2b 100644 --- a/source3/libads/kerberos_verify.c +++ b/source3/libads/kerberos_verify.c @@ -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 */ - - 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); + 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); + + 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))); diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c index be6943b..b33800f 100644 --- a/source3/libnet/libnet_join.c +++ b/source3/libnet/libnet_join.c @@ -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; } diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index 6438888..d672b37 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -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) diff --git a/source3/rpc_server/srv_pipe.c b/source3/rpc_server/srv_pipe.c index cbe6978..924226b 100644 --- a/source3/rpc_server/srv_pipe.c +++ b/source3/rpc_server/srv_pipe.c @@ -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); diff --git a/source3/smbd/negprot.c b/source3/smbd/negprot.c index 729d144..57608a9 100644 --- a/source3/smbd/negprot.c +++ b/source3/smbd/negprot.c @@ -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); diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c index a2ad56b..7a03ef7 100644 --- a/source3/smbd/sesssetup.c +++ b/source3/smbd/sesssetup.c @@ -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); diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c index 766f321..03786e2 100644 --- a/source3/utils/net_ads.c +++ b/source3/utils/net_ads.c @@ -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); diff --git a/source3/winbindd/winbindd_dual.c b/source3/winbindd/winbindd_dual.c index 1385c76..d40bab9 100644 --- a/source3/winbindd/winbindd_dual.c +++ b/source3/winbindd/winbindd_dual.c @@ -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; -- Samba Shared Repository