s3-keytab: fix keytab array NULL termination.
[samba.git] / source3 / libads / kerberos_keytab.c
index 94698c6cc29f17c7ca5a3ddd9818b26134eb2709..ae3d80e39c2bf6e50ae713374d656540c5ed0da0 100644 (file)
@@ -49,6 +49,7 @@ static krb5_error_code seek_and_delete_old_entries(krb5_context context,
        krb5_keytab_entry kt_entry;
        krb5_keytab_entry zero_kt_entry;
        char *ktprinc = NULL;
+       krb5_kvno old_kvno = kvno - 1;
 
        ZERO_STRUCT(cursor);
        ZERO_STRUCT(zero_csr);
@@ -115,12 +116,14 @@ static krb5_error_code seek_and_delete_old_entries(krb5_context context,
                 * changes, all kerberizied sessions will 'break' until either
                 * the client reboots or the client's session key expires and
                 * they get a new session ticket with the new kvno.
+                * Some keytab files only store the kvno in 8bits, limit
+                * the compare accordingly.
                 */
 
-               if (!flush && (kt_entry.vno == kvno - 1)) {
+               if (!flush && ((kt_entry.vno & 0xff) == (old_kvno & 0xff))) {
                        DEBUG(5, (__location__ ": Saving previous (kvno %d) "
                                  "entry for principal: %s.\n",
-                                 kvno - 1, princ_s));
+                                 old_kvno, princ_s));
                        continue;
                }
 
@@ -250,6 +253,8 @@ out:
        return (int)ret;
 }
 
+#ifdef HAVE_ADS
+
 /**********************************************************************
  Adds a single service principal, i.e. 'host' to the system keytab
 ***********************************************************************/
@@ -261,9 +266,15 @@ int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc)
        krb5_keytab keytab = NULL;
        krb5_data password;
        krb5_kvno kvno;
-        krb5_enctype enctypes[4] = {
+        krb5_enctype enctypes[6] = {
                ENCTYPE_DES_CBC_CRC,
                ENCTYPE_DES_CBC_MD5,
+#ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
+               ENCTYPE_AES128_CTS_HMAC_SHA1_96,
+#endif
+#ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
+               ENCTYPE_AES256_CTS_HMAC_SHA1_96,
+#endif
                ENCTYPE_ARCFOUR_HMAC,
                0
        };
@@ -314,7 +325,7 @@ int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc)
                goto out;
        }
 
-       my_fqdn = ads_get_dnshostname(ads, tmpctx, global_myname());
+       my_fqdn = ads_get_dnshostname(ads, tmpctx, lp_netbios_name());
        if (!my_fqdn) {
                DEBUG(0, (__location__ ": unable to determine machine "
                          "account's dns name in AD!\n"));
@@ -322,7 +333,7 @@ int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc)
                goto out;
        }
 
-       machine_name = ads_get_samaccountname(ads, tmpctx, global_myname());
+       machine_name = ads_get_samaccountname(ads, tmpctx, lp_netbios_name());
        if (!machine_name) {
                DEBUG(0, (__location__ ": unable to determine machine "
                          "account's short name in AD!\n"));
@@ -362,7 +373,7 @@ int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc)
                short_princ_s = talloc_asprintf(tmpctx, "%s/%s@%s",
                                                srvPrinc, machine_name,
                                                lp_realm());
-               if (!princ_s) {
+               if (short_princ_s == NULL) {
                        ret = -1;
                        goto out;
                }
@@ -378,7 +389,7 @@ int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc)
                                  "'%s'\n", princ_s));
 
                        aderr = ads_add_service_principal_name(ads,
-                                       global_myname(), my_fqdn, srvPrinc);
+                                       lp_netbios_name(), my_fqdn, srvPrinc);
                        if (!ADS_ERR_OK(aderr)) {
                                DEBUG(1, (__location__ ": failed to "
                                         "ads_add_service_principal_name.\n"));
@@ -387,7 +398,7 @@ int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc)
                }
        }
 
-       kvno = (krb5_kvno)ads_get_machine_kvno(ads, global_myname());
+       kvno = (krb5_kvno)ads_get_machine_kvno(ads, lp_netbios_name());
        if (kvno == -1) {
                /* -1 indicates failure, everything else is OK */
                DEBUG(1, (__location__ ": ads_get_machine_kvno failed to "
@@ -456,7 +467,7 @@ int ads_keytab_flush(ADS_STRUCT *ads)
                goto out;
        }
 
-       kvno = (krb5_kvno)ads_get_machine_kvno(ads, global_myname());
+       kvno = (krb5_kvno)ads_get_machine_kvno(ads, lp_netbios_name());
        if (kvno == -1) {
                /* -1 indicates a failure */
                DEBUG(1, (__location__ ": Error determining the kvno.\n"));
@@ -470,7 +481,7 @@ int ads_keytab_flush(ADS_STRUCT *ads)
                goto out;
        }
 
-       aderr = ads_clear_service_principal_names(ads, global_myname());
+       aderr = ads_clear_service_principal_names(ads, lp_netbios_name());
        if (!ADS_ERR_OK(aderr)) {
                DEBUG(1, (__location__ ": Error while clearing service "
                          "principal listings in LDAP.\n"));
@@ -499,20 +510,57 @@ int ads_keytab_create_default(ADS_STRUCT *ads)
        krb5_kt_cursor cursor;
        krb5_keytab_entry kt_entry;
        krb5_kvno kvno;
-       int i, found = 0;
+       size_t found = 0;
        char *sam_account_name, *upn;
        char **oldEntries = NULL, *princ_s[26];
-       TALLOC_CTX *tmpctx = NULL;
+       TALLOC_CTX *frame;
        char *machine_name;
+       char **spn_array;
+       size_t num_spns;
+       size_t i;
+       ADS_STATUS status;
 
-       /* these are the main ones we need */
-       ret = ads_keytab_add_entry(ads, "host");
-       if (ret != 0) {
-               DEBUG(1, (__location__ ": ads_keytab_add_entry failed while "
-                         "adding 'host' principal.\n"));
-               return ret;
+       frame = talloc_stackframe();
+       if (frame == NULL) {
+               ret = -1;
+               goto done;
        }
 
+       status = ads_get_service_principal_names(frame,
+                                                ads,
+                                                lp_netbios_name(),
+                                                &spn_array,
+                                                &num_spns);
+       if (!ADS_ERR_OK(status)) {
+               ret = -1;
+               goto done;
+       }
+
+       for (i = 0; i < num_spns; i++) {
+               char *srv_princ;
+               char *p;
+
+               srv_princ = strlower_talloc(frame, spn_array[i]);
+               if (srv_princ == NULL) {
+                       ret = -1;
+                       goto done;
+               }
+
+               p = strchr_m(srv_princ, '/');
+               if (p == NULL) {
+                       continue;
+               }
+               p[0] = '\0';
+
+               /* Add the SPNs found on the DC */
+               ret = ads_keytab_add_entry(ads, srv_princ);
+               if (ret != 0) {
+                       DEBUG(1, ("ads_keytab_add_entry failed while "
+                                 "adding '%s' principal.\n",
+                                 spn_array[i]));
+                       goto done;
+               }
+       }
 
 #if 0  /* don't create the CIFS/... keytab entries since no one except smbd
           really needs them and we will fall back to verifying against
@@ -535,24 +583,17 @@ int ads_keytab_create_default(ADS_STRUCT *ads)
        if (ret) {
                DEBUG(1, (__location__ ": could not krb5_init_context: %s\n",
                          error_message(ret)));
-               return ret;
-       }
-
-       tmpctx = talloc_init(__location__);
-       if (!tmpctx) {
-               DEBUG(0, (__location__ ": talloc_init() failed!\n"));
-               ret = -1;
                goto done;
        }
 
-       machine_name = talloc_strdup(tmpctx, global_myname());
+       machine_name = talloc_strdup(frame, lp_netbios_name());
        if (!machine_name) {
                ret = -1;
                goto done;
        }
 
        /* now add the userPrincipalName and sAMAccountName entries */
-       sam_account_name = ads_get_samaccountname(ads, tmpctx, machine_name);
+       sam_account_name = ads_get_samaccountname(ads, frame, machine_name);
        if (!sam_account_name) {
                DEBUG(0, (__location__ ": unable to determine machine "
                          "account's name in AD!\n"));
@@ -562,7 +603,10 @@ int ads_keytab_create_default(ADS_STRUCT *ads)
 
        /* upper case the sAMAccountName to make it easier for apps to
           know what case to use in the keytab file */
-       strupper_m(sam_account_name);
+       if (!strupper_m(sam_account_name)) {
+               ret = -1;
+               goto done;
+       }
 
        ret = ads_keytab_add_entry(ads, sam_account_name);
        if (ret != 0) {
@@ -573,7 +617,7 @@ int ads_keytab_create_default(ADS_STRUCT *ads)
        }
 
        /* remember that not every machine account will have a upn */
-       upn = ads_get_upn(ads, tmpctx, machine_name);
+       upn = ads_get_upn(ads, frame, machine_name);
        if (upn) {
                ret = ads_keytab_add_entry(ads, upn);
                if (ret != 0) {
@@ -585,7 +629,7 @@ int ads_keytab_create_default(ADS_STRUCT *ads)
 
        /* Now loop through the keytab and update any other existing entries */
        kvno = (krb5_kvno)ads_get_machine_kvno(ads, machine_name);
-       if (kvno == -1) {
+       if (kvno == (krb5_kvno)-1) {
                DEBUG(1, (__location__ ": ads_get_machine_kvno() failed to "
                          "determine the system's kvno.\n"));
                goto done;
@@ -618,19 +662,18 @@ int ads_keytab_create_default(ADS_STRUCT *ads)
         * have a race condition where someone else could add entries after
         * we've counted them. Re-open asap to minimise the race. JRA.
         */
-       DEBUG(3, (__location__ ": Found %d entries in the keytab.\n", found));
+       DEBUG(3, (__location__ ": Found %zd entries in the keytab.\n", found));
        if (!found) {
                goto done;
        }
 
-       oldEntries = talloc_array(tmpctx, char *, found);
+       oldEntries = talloc_zero_array(frame, char *, found + 1);
        if (!oldEntries) {
                DEBUG(1, (__location__ ": Failed to allocate space to store "
                          "the old keytab entries (talloc failed?).\n"));
                ret = -1;
                goto done;
        }
-       memset(oldEntries, '\0', found * sizeof(char *));
 
        ret = krb5_kt_start_seq_get(context, keytab, &cursor);
        if (ret == KRB5_KT_END || ret == ENOENT) {
@@ -697,7 +740,7 @@ int ads_keytab_create_default(ADS_STRUCT *ads)
 
 done:
        TALLOC_FREE(oldEntries);
-       TALLOC_FREE(tmpctx);
+       TALLOC_FREE(frame);
 
        {
                krb5_keytab_entry zero_kt_entry;
@@ -724,6 +767,8 @@ done:
        return ret;
 }
 
+#endif /* HAVE_ADS */
+
 /**********************************************************************
  List system keytab.
 ***********************************************************************/
@@ -756,10 +801,11 @@ int ads_keytab_list(const char *keytab_name)
 
        ret = krb5_kt_start_seq_get(context, keytab, &cursor);
        if (ret) {
+               ZERO_STRUCT(cursor);
                goto out;
        }
 
-       printf("Vno  Type        Principal\n");
+       printf("Vno  Type                                        Principal\n");
 
        while (krb5_kt_next_entry(context, keytab, &kt_entry, &cursor) == 0) {
 
@@ -782,7 +828,7 @@ int ads_keytab_list(const char *keytab_name)
                        goto out;
                }
 
-               printf("%3d  %s\t\t %s\n", kt_entry.vno, etype_s, princ_s);
+               printf("%3d  %-43s %s\n", kt_entry.vno, etype_s, princ_s);
 
                TALLOC_FREE(princ_s);
                SAFE_FREE(etype_s);