diff options
-rw-r--r-- | source3/include/includes.h | 19 | ||||
-rw-r--r-- | source3/include/proto.h | 3 | ||||
-rw-r--r-- | source3/libads/kerberos_verify.c | 129 | ||||
-rw-r--r-- | source3/libnet/libnet_join.c | 2 | ||||
-rw-r--r-- | source3/param/loadparm.c | 33 | ||||
-rw-r--r-- | source3/rpc_server/srv_pipe.c | 2 | ||||
-rw-r--r-- | source3/smbd/negprot.c | 2 | ||||
-rw-r--r-- | source3/smbd/sesssetup.c | 4 | ||||
-rw-r--r-- | source3/utils/net_ads.c | 8 | ||||
-rw-r--r-- | source3/winbindd/winbindd_dual.c | 2 |
10 files changed, 170 insertions, 34 deletions
diff --git a/source3/include/includes.h b/source3/include/includes.h index c58ebcdbfe..ebd8923769 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 c97adaa1c0..285b44dcde 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 de3fdeb9de..4483d2be58 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 be6943bad9..b33800f20d 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 6438888942..d672b372cf 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 cbe697817a..924226bc4f 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 729d144ea1..57608a9b40 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 a2ad56bea1..7a03ef7f3c 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 766f3216f0..03786e2e17 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 1385c76bae..d40bab94ef 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; |