summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/includes.h19
-rw-r--r--source3/include/proto.h3
-rw-r--r--source3/libads/kerberos_verify.c129
-rw-r--r--source3/libnet/libnet_join.c2
-rw-r--r--source3/param/loadparm.c33
-rw-r--r--source3/rpc_server/srv_pipe.c2
-rw-r--r--source3/smbd/negprot.c2
-rw-r--r--source3/smbd/sesssetup.c4
-rw-r--r--source3/utils/net_ads.c8
-rw-r--r--source3/winbindd/winbindd_dual.c2
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;