r5762: Modified version of patch from Michael Brown <mbrown@fensystems.co.uk> to...
authorJeremy Allison <jra@samba.org>
Sat, 12 Mar 2005 01:28:10 +0000 (01:28 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 15:56:00 +0000 (10:56 -0500)
insentively search for a principal match on logon verification in the system
keytab. UNTESTED (although it compiles). Please test.
Jeremy.
(This used to be commit 1ace2ca1be65b4d6e92a98040fd09fdca74e8c8a)

source3/libads/kerberos_verify.c

index d73fc28a2966dbaf773643d7044fd9f14971d2ed..d6cca793187f0f7f6afc4a088aaa3549aa146a11 100644 (file)
@@ -42,12 +42,33 @@ static BOOL ads_keytab_verify_ticket(krb5_context context, krb5_auth_context aut
        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) {
@@ -55,74 +76,87 @@ static BOOL ads_keytab_verify_ticket(krb5_context context, krb5_auth_context aut
                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;
+                       }
+
+                       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;
+                                       }
+                               }
+                       }
+
+                       /* Free the name we parsed. */
+                       krb5_free_unparsed_name(context, entry_princ_s);
+                       entry_princ_s = NULL;
+
+                       /* 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);
+       }
 
-       fstrcpy(my_NAME, global_myname());
-       strupper_m(my_NAME);
+       ZERO_STRUCT(kt_cursor);
 
-       my_fqdn[0] = '\0';
-       name_to_fqdn(my_fqdn, global_myname());
-       strlower_m(my_fqdn);
-
-       p_fqdn = strchr_m(my_fqdn, '.');
-       fstrcpy(my_Fqdn, my_NAME);
-       if (p_fqdn) {
-               fstrcat(my_Fqdn, p_fqdn);
-       }
-
-        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());
-
-       /* 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;
-               }
-               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)));
+  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(10,("krb5_rd_req succeeded for principal %s\n", host_princ_s[i]));
-                       auth_ok = True;
-                       break;
-                }
+                       DEBUG(3, ("ads_keytab_verify_ticket: krb5_rd_req failed for all %d matched keytab principals\n",
+                               number_matched_principals));
+               }
        }
 
-       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);