Catching more principals in ads_keytab_verify_ticket()

Jeremy Allison jra at samba.org
Sat Mar 12 01:25:46 GMT 2005


On Thu, Mar 10, 2005 at 03:56:03AM -0800, Doug VanLeuven wrote:
> Jeremy Allison wrote:
> 
> >I'm not going to add either patch until you huys have both
> >agreed. When you do - re-mail me the patch you want going in
> >and I'll look at that.
> >
> >The kerberos keytab stuff is complex enough that the last
> >thing I want to see is "warring patches" that fix different
> >things for different people.
> > 
> >
> The rc4-hmac works ok.
> The des-cbc-md5 works ok.
> 
> After having studied it and run the experiments, it seems like a real 
> good idea.
> I didn't change anything from his submittal except a couple debug 
> statements.  I'm finding it really handy to have a message all key 
> matches failed.  Sort of a heads up something is missing from the keytab.
> 
> Thanks a lot Michael, it's a lot cleaner.
> 
> Jeremy, I'm still working on what to do for libads/kerberos_keytab.c.  
> Some issues came up during the des testing that have a direct bearing on 
> bug 2414 you asked about.
> 
> Regards, Doug

Ok, here's my version of Michael's patch. Re-coded for Samba keytab
requirements - also frees entries after reading. I'm going to check into
SAMBA_3_0 and HEAD SVN trees. Please test.

Thanks,

	Jeremy.
-------------- next part --------------
Index: libads/kerberos_verify.c
===================================================================
--- libads/kerberos_verify.c	(revision 5755)
+++ libads/kerberos_verify.c	(working copy)
@@ -42,88 +42,122 @@
 	krb5_error_code ret = 0;
 	BOOL auth_ok = False;
 	krb5_keytab keytab = NULL;
-	fstring my_fqdn, my_name;
-	fstring my_Fqdn, my_NAME;
-	char *p_fqdn;
-	char *host_princ_s[18];
-	krb5_principal host_princ;
+	krb5_kt_cursor kt_cursor;
+	krb5_keytab_entry kt_entry;
+	char *valid_princ_formats[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
+	char *entry_princ_s = NULL;
+	fstring my_name, my_fqdn;
 	int i;
+	int number_matched_principals = 0;
 
+	/* Generate the list of principal names which we expect
+	 * clients might want to use for authenticating to the file
+	 * service.  We allow name$,{host,cifs}/{name,fqdn,name.REALM}. */
+
+	fstrcpy(my_name, global_myname());
+
+	my_fqdn[0] = '\0';
+	name_to_fqdn(my_fqdn, global_myname());
+
+	asprintf(&valid_princ_formats[0], "%s$@%s", my_name, lp_realm());
+	asprintf(&valid_princ_formats[1], "host/%s@%s", my_name, lp_realm());
+	asprintf(&valid_princ_formats[2], "host/%s@%s", my_fqdn, lp_realm());
+	asprintf(&valid_princ_formats[3], "host/%s.%s@%s", my_name, lp_realm(), lp_realm());
+	asprintf(&valid_princ_formats[4], "cifs/%s@%s", my_name, lp_realm());
+	asprintf(&valid_princ_formats[5], "cifs/%s@%s", my_fqdn, lp_realm());
+	asprintf(&valid_princ_formats[6], "cifs/%s.%s@%s", my_name, lp_realm(), lp_realm());
+
+	ZERO_STRUCT(kt_entry);
+	ZERO_STRUCT(kt_cursor);
+
 	ret = krb5_kt_default(context, &keytab);
 	if (ret) {
 		DEBUG(1, ("ads_keytab_verify_ticket: krb5_kt_default failed (%s)\n", error_message(ret)));
 		goto out;
 	}
 
-	/* Generate the list of principal names which we expect clients might
-	 * want to use for authenticating to the file service. */
+	/* Iterate through the keytab.  For each key, if the principal
+	 * name case-insensitively matches one of the allowed formats,
+	 * try verifying the ticket using that principal. */
 
-	fstrcpy(my_name, global_myname());
-	strlower_m(my_name);
+	ret = krb5_kt_start_seq_get(context, keytab, &kt_cursor);
+	if (ret) {
+		DEBUG(1, ("ads_keytab_verify_ticket: krb5_kt_start_seq_get failed (%s)\n", error_message(ret)));
+		goto out;
+	}
+  
+	ret = krb5_kt_start_seq_get(context, keytab, &kt_cursor);
+	if (ret != KRB5_KT_END && ret != ENOENT ) {
+		while (!auth_ok && (krb5_kt_next_entry(context, keytab, &kt_entry, &kt_cursor) == 0)) {
+			ret = krb5_unparse_name(context, kt_entry.principal, &entry_princ_s);
+			if (ret) {
+				DEBUG(1, ("ads_keytab_verify_ticket: krb5_unparse_name failed (%s)\n", error_message(ret)));
+				goto out;
+			}
 
-	fstrcpy(my_NAME, global_myname());
-	strupper_m(my_NAME);
+			for (i = 0; i < sizeof(valid_princ_formats) / sizeof(valid_princ_formats[0]); i++) {
+				if (strequal(entry_princ_s, valid_princ_formats[i])) {
+					number_matched_principals++;
+					p_packet->length = ticket->length;
+					p_packet->data = (krb5_pointer)ticket->data;
+					*pp_tkt = NULL;
+					ret = krb5_rd_req(context, &auth_context, p_packet, kt_entry.principal, keytab, NULL, pp_tkt);
+					if (ret) {
+						DEBUG(10, ("ads_keytab_verify_ticket: krb5_rd_req(%s) failed: %s\n",
+							entry_princ_s, error_message(ret)));
+					} else {
+						DEBUG(3,("ads_keytab_verify_ticket: krb5_rd_req succeeded for principal %s\n",
+							entry_princ_s));
+						auth_ok = True;
+						break;
+					}
+				}
+			}
 
-	my_fqdn[0] = '\0';
-	name_to_fqdn(my_fqdn, global_myname());
-	strlower_m(my_fqdn);
+			/* Free the name we parsed. */
+			krb5_free_unparsed_name(context, entry_princ_s);
+			entry_princ_s = NULL;
 
-	p_fqdn = strchr_m(my_fqdn, '.');
-	fstrcpy(my_Fqdn, my_NAME);
-	if (p_fqdn) {
-		fstrcat(my_Fqdn, p_fqdn);
+			/* Free the entry we just read. */
+			smb_krb5_kt_free_entry(context, &kt_entry);
+			ZERO_STRUCT(kt_entry);
+		}
+		krb5_kt_end_seq_get(context, keytab, &kt_cursor);
 	}
 
-        asprintf(&host_princ_s[0], "%s$@%s", my_name, lp_realm());
-        asprintf(&host_princ_s[1], "%s$@%s", my_NAME, lp_realm());
-        asprintf(&host_princ_s[2], "host/%s@%s", my_name, lp_realm());
-        asprintf(&host_princ_s[3], "host/%s@%s", my_NAME, lp_realm());
-        asprintf(&host_princ_s[4], "host/%s@%s", my_fqdn, lp_realm());
-        asprintf(&host_princ_s[5], "host/%s@%s", my_Fqdn, lp_realm());
-        asprintf(&host_princ_s[6], "HOST/%s@%s", my_name, lp_realm());
-        asprintf(&host_princ_s[7], "HOST/%s@%s", my_NAME, lp_realm());
-        asprintf(&host_princ_s[8], "HOST/%s@%s", my_fqdn, lp_realm());
-        asprintf(&host_princ_s[9], "HOST/%s@%s", my_Fqdn, lp_realm());
-        asprintf(&host_princ_s[10], "cifs/%s@%s", my_name, lp_realm());
-        asprintf(&host_princ_s[11], "cifs/%s@%s", my_NAME, lp_realm());
-        asprintf(&host_princ_s[12], "cifs/%s@%s", my_fqdn, lp_realm());
-        asprintf(&host_princ_s[13], "cifs/%s@%s", my_Fqdn, lp_realm());
-        asprintf(&host_princ_s[14], "CIFS/%s@%s", my_name, lp_realm());
-        asprintf(&host_princ_s[15], "CIFS/%s@%s", my_NAME, lp_realm());
-        asprintf(&host_princ_s[16], "CIFS/%s@%s", my_fqdn, lp_realm());
-        asprintf(&host_princ_s[17], "CIFS/%s@%s", my_Fqdn, lp_realm());
+	ZERO_STRUCT(kt_cursor);
 
-	/* Now try to verify the ticket using the key associated with each of
-	 * the principals which we think clients will expect us to be
-	 * participating as. */
-	for (i = 0; i < sizeof(host_princ_s) / sizeof(host_princ_s[0]); i++) {
-		host_princ = NULL;
-		ret = krb5_parse_name(context, host_princ_s[i], &host_princ);
-		if (ret) {
-			DEBUG(1, ("ads_keytab_verify_ticket: krb5_parse_name(%s) failed (%s)\n",
-				host_princ_s[i], error_message(ret)));
-			goto out;
+  out:
+
+	if (!auth_ok) {
+		if (!number_matched_principals) {
+			DEBUG(3, ("ads_keytab_verify_ticket: no keytab principals matched expected file service name.\n"));
+		} else {
+			DEBUG(3, ("ads_keytab_verify_ticket: krb5_rd_req failed for all %d matched keytab principals\n",
+				number_matched_principals));
 		}
-		p_packet->length = ticket->length;
-		p_packet->data = (krb5_pointer)ticket->data;
-		*pp_tkt = NULL;
-		ret = krb5_rd_req(context, &auth_context, p_packet, host_princ, keytab, NULL, pp_tkt);
-		krb5_free_principal(context, host_princ);
-		if (ret) {
-			DEBUG(10, ("krb5_rd_req(%s) failed: %s\n", host_princ_s[i], error_message(ret)));
-		} else {
-			DEBUG(10,("krb5_rd_req succeeded for principal %s\n", host_princ_s[i]));
-			auth_ok = True;
-			break;
-                }
 	}
 
-	for (i = 0; i < sizeof(host_princ_s) / sizeof(host_princ_s[0]); i++) {
-		SAFE_FREE(host_princ_s[i]);
+	if (entry_princ_s) {
+		krb5_free_unparsed_name(context, entry_princ_s);
 	}
 
-  out:
+	{
+		krb5_keytab_entry zero_kt_entry;
+		ZERO_STRUCT(zero_kt_entry);
+		if (memcmp(&zero_kt_entry, &kt_entry, sizeof(krb5_keytab_entry))) {
+			smb_krb5_kt_free_entry(context, &kt_entry);
+		}
+	}
 
+	{
+		krb5_kt_cursor zero_csr;
+		ZERO_STRUCT(zero_csr);
+		if ((memcmp(&kt_cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && keytab) {
+			krb5_kt_end_seq_get(context, keytab, &kt_cursor);
+		}
+	}
+
 	if (keytab) {
 		krb5_kt_close(context, keytab);
 	}


More information about the samba-technical mailing list