Add two new parameters to control how we verify kerberos tickets. Removes lp_use_kerb...
authorDan Sledz <dsledz@isilon.com>
Fri, 16 Jan 2009 01:02:41 +0000 (17:02 -0800)
committerSteven Danneman <steven.danneman@isilon.com>
Mon, 2 Feb 2009 04:23:31 +0000 (20:23 -0800)
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.

source3/include/includes.h
source3/include/proto.h
source3/libads/kerberos_verify.c
source3/libnet/libnet_join.c
source3/param/loadparm.c
source3/rpc_server/srv_pipe.c
source3/smbd/negprot.c
source3/smbd/sesssetup.c
source3/utils/net_ads.c
source3/winbindd/winbindd_dual.c

index c58ebcdbfe3b2b19966be37d5614cc3e1a3668fe..ebd8923769109a4e216b709d69ab7e0aa5baa24d 100644 (file)
@@ -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);
index c97adaa1c0af0cbfe72d2fb16924de738fe28398..285b44dcdebdc0449cfb391a47a76f18543e2165 100644 (file)
@@ -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);
index de3fdeb9de6cdcd81bd78e6820453280d867f75c..4483d2be58ef13f86734978d1c60661dd5d3f6bf 100644 (file)
 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)));
index be6943bad97159fdc10485123fdc51585b732428..b33800f20db8eb4dce7e5aadea5d352a466df954 100644 (file)
@@ -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;
        }
 
index 6438888942fe5fb474c1bce88cbcb04b19df2cc7..d672b372cfb09327100f25f157ecd38323403445 100644 (file)
@@ -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)
index cbe697817a2b856e5ee70815032b461478b55dd0..924226bc4f2ad61f75d19cfee14973bccd470bb1 100644 (file)
@@ -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);
index 729d144ea1bae4e81d9637a62befb802be282a54..57608a9b406785b507a29af8fe74b7b4ecebac02 100644 (file)
@@ -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);
index a2ad56bea16f94495840ca032cb13b4a9c646dfd..7a03ef7f3cc6a324a5e8d4b3a3fedefd2eebfc7c 100644 (file)
@@ -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);
index 766f3216f0b9c200c9c0ce246d2f75a34dc21caa..03786e2e177c56f260eaa92be5a8c94f5428d970 100644 (file)
@@ -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);
index 1385c76bae497a09ff94de217018d836c5daeff9..d40bab94ef9e5b33ed54ce729ee8f19bac348732 100644 (file)
@@ -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;