LCOV - code coverage report
Current view: top level - source4/auth/kerberos - srv_keytab.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 95 145 65.5 %
Date: 2024-02-28 12:06:22 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    Kerberos utility functions
       5             : 
       6             :    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             : 
      19             :    You should have received a copy of the GNU General Public License
      20             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      21             : */
      22             : 
      23             : /**
      24             :  * @file srv_keytab.c
      25             :  *
      26             :  * @brief Kerberos keytab utility functions
      27             :  *
      28             :  */
      29             : 
      30             : #include "includes.h"
      31             : #include "system/kerberos.h"
      32             : #include "auth/credentials/credentials.h"
      33             : #include "auth/kerberos/kerberos.h"
      34             : #include "auth/kerberos/kerberos_util.h"
      35             : #include "auth/kerberos/kerberos_srv_keytab.h"
      36             : 
      37         348 : static void keytab_principals_free(krb5_context context,
      38             :                                    uint32_t num_principals,
      39             :                                    krb5_principal *set)
      40             : {
      41          26 :         uint32_t i;
      42             : 
      43        1178 :         for (i = 0; i < num_principals; i++) {
      44         830 :                 krb5_free_principal(context, set[i]);
      45             :         }
      46         322 : }
      47             : 
      48         345 : static krb5_error_code keytab_add_keys(TALLOC_CTX *parent_ctx,
      49             :                                        uint32_t num_principals,
      50             :                                        krb5_principal *principals,
      51             :                                        krb5_principal salt_princ,
      52             :                                        int kvno,
      53             :                                        const char *password_s,
      54             :                                        krb5_context context,
      55             :                                        krb5_enctype *enctypes,
      56             :                                        krb5_keytab keytab,
      57             :                                        const char **error_string)
      58             : {
      59          26 :         unsigned int i, p;
      60          26 :         krb5_error_code ret;
      61          26 :         krb5_data password;
      62          26 :         char *unparsed;
      63             : 
      64         345 :         password.data = discard_const_p(char, password_s);
      65         345 :         password.length = strlen(password_s);
      66             : 
      67        1380 :         for (i = 0; enctypes[i]; i++) {
      68          78 :                 krb5_keytab_entry entry;
      69             : 
      70        1035 :                 ZERO_STRUCT(entry);
      71             : 
      72        1035 :                 ret = smb_krb5_create_key_from_string(context,
      73             :                                                       salt_princ,
      74             :                                                       NULL,
      75             :                                                       &password,
      76         957 :                                                       enctypes[i],
      77             :                                                       KRB5_KT_KEY(&entry));
      78        1035 :                 if (ret != 0) {
      79           0 :                         *error_string = talloc_strdup(parent_ctx,
      80             :                                                       "Failed to create key from string");
      81           0 :                         return ret;
      82             :                 }
      83             : 
      84        1035 :                 entry.vno = kvno;
      85             : 
      86        3507 :                 for (p = 0; p < num_principals; p++) {
      87        2472 :                         unparsed = NULL;
      88        2472 :                         entry.principal = principals[p];
      89        2472 :                         ret = krb5_kt_add_entry(context, keytab, &entry);
      90        2472 :                         if (ret != 0) {
      91           0 :                                 char *k5_error_string =
      92           0 :                                         smb_get_krb5_error_message(context,
      93             :                                                                    ret, NULL);
      94           0 :                                 krb5_unparse_name(context,
      95           0 :                                                 principals[p], &unparsed);
      96           0 :                                 *error_string = talloc_asprintf(parent_ctx,
      97             :                                         "Failed to add enctype %d entry for "
      98             :                                         "%s(kvno %d) to keytab: %s\n",
      99           0 :                                         (int)enctypes[i], unparsed,
     100             :                                         kvno, k5_error_string);
     101             : 
     102           0 :                                 free(unparsed);
     103           0 :                                 talloc_free(k5_error_string);
     104           0 :                                 krb5_free_keyblock_contents(context,
     105             :                                                             KRB5_KT_KEY(&entry));
     106           0 :                                 return ret;
     107             :                         }
     108             : 
     109        2472 :                         DEBUG(5, ("Added key (kvno %d) to keytab (enctype %d)\n",
     110             :                                   kvno, (int)enctypes[i]));
     111             :                 }
     112        1035 :                 krb5_free_keyblock_contents(context, KRB5_KT_KEY(&entry));
     113             :         }
     114         319 :         return 0;
     115             : }
     116             : 
     117         346 : static krb5_error_code create_keytab(TALLOC_CTX *parent_ctx,
     118             :                                      const char *samAccountName,
     119             :                                      const char *realm,
     120             :                                      const char *saltPrincipal,
     121             :                                      int kvno,
     122             :                                      const char *new_secret,
     123             :                                      const char *old_secret,
     124             :                                      uint32_t supp_enctypes,
     125             :                                      uint32_t num_principals,
     126             :                                      krb5_principal *principals,
     127             :                                      krb5_context context,
     128             :                                      krb5_keytab keytab,
     129             :                                      bool add_old,
     130             :                                      const char **perror_string)
     131             : {
     132          26 :         krb5_error_code ret;
     133         346 :         krb5_principal salt_princ = NULL;
     134          26 :         krb5_enctype *enctypes;
     135          26 :         TALLOC_CTX *mem_ctx;
     136         346 :         const char *error_string = NULL;
     137             : 
     138         346 :         if (!new_secret) {
     139             :                 /* There is no password here, so nothing to do */
     140           1 :                 return 0;
     141             :         }
     142             : 
     143         345 :         mem_ctx = talloc_new(parent_ctx);
     144         345 :         if (!mem_ctx) {
     145           0 :                 *perror_string = talloc_strdup(parent_ctx,
     146             :                         "unable to allocate tmp_ctx for create_keytab");
     147           0 :                 return ENOMEM;
     148             :         }
     149             : 
     150             :         /* The salt used to generate these entries may be different however,
     151             :          * fetch that */
     152         345 :         ret = krb5_parse_name(context, saltPrincipal, &salt_princ);
     153         345 :         if (ret) {
     154           0 :                 *perror_string = smb_get_krb5_error_message(context,
     155             :                                                            ret,
     156             :                                                            parent_ctx);
     157           0 :                 talloc_free(mem_ctx);
     158           0 :                 return ret;
     159             :         }
     160             : 
     161         345 :         ret = ms_suptypes_to_ietf_enctypes(mem_ctx, supp_enctypes, &enctypes);
     162         345 :         if (ret) {
     163           0 :                 *perror_string = talloc_asprintf(parent_ctx,
     164             :                                         "create_keytab: generating list of "
     165             :                                         "encryption types failed (%s)\n",
     166             :                                         smb_get_krb5_error_message(context,
     167             :                                                                 ret, mem_ctx));
     168           0 :                 goto done;
     169             :         }
     170             : 
     171         345 :         ret = keytab_add_keys(mem_ctx,
     172             :                               num_principals,
     173             :                               principals,
     174             :                               salt_princ, kvno, new_secret,
     175             :                               context, enctypes, keytab, &error_string);
     176         345 :         if (ret) {
     177           0 :                 *perror_string = talloc_steal(parent_ctx, error_string);
     178           0 :                 goto done;
     179             :         }
     180             : 
     181         345 :         if (old_secret && add_old && kvno != 0) {
     182           0 :                 ret = keytab_add_keys(mem_ctx,
     183             :                                       num_principals,
     184             :                                       principals,
     185             :                                       salt_princ, kvno - 1, old_secret,
     186             :                                       context, enctypes, keytab, &error_string);
     187           0 :                 if (ret) {
     188           0 :                         *perror_string = talloc_steal(parent_ctx, error_string);
     189             :                 }
     190             :         }
     191             : 
     192         345 : done:
     193         345 :         krb5_free_principal(context, salt_princ);
     194         345 :         talloc_free(mem_ctx);
     195         345 :         return ret;
     196             : }
     197             : 
     198             : /**
     199             :  * @brief Update a Kerberos keytab and removes any obsolete keytab entries.
     200             :  *
     201             :  * If the keytab does not exist, this function will create one.
     202             :  *
     203             :  * @param[in] parent_ctx        Talloc memory context
     204             :  * @param[in] context           Kerberos context
     205             :  * @param[in] keytab_name       Keytab to open
     206             :  * @param[in] samAccountName    User account to update
     207             :  * @param[in] realm             Kerberos realm
     208             :  * @param[in] SPNs              Service principal names to update
     209             :  * @param[in] num_SPNs          Length of SPNs
     210             :  * @param[in] saltPrincipal     Salt used for AES encryption.
     211             :  *                              Required, unless delete_all_kvno is set.
     212             :  * @param[in] old_secret        Old password
     213             :  * @param[in] new_secret        New password
     214             :  * @param[in] kvno              Current key version number
     215             :  * @param[in] supp_enctypes     msDS-SupportedEncryptionTypes bit-field
     216             :  * @param[in] delete_all_kvno   Removes all obsolete entries, without
     217             :  *                              recreating the keytab.
     218             :  * @param[out] _keytab          If supplied, returns the keytab
     219             :  * @param[out] perror_string    Error string on failure
     220             :  *
     221             :  * @return                      0 on success, errno on failure
     222             :  */
     223         348 : krb5_error_code smb_krb5_update_keytab(TALLOC_CTX *parent_ctx,
     224             :                                 krb5_context context,
     225             :                                 const char *keytab_name,
     226             :                                 const char *samAccountName,
     227             :                                 const char *realm,
     228             :                                 const char **SPNs,
     229             :                                 int num_SPNs,
     230             :                                 const char *saltPrincipal,
     231             :                                 const char *new_secret,
     232             :                                 const char *old_secret,
     233             :                                 int kvno,
     234             :                                 uint32_t supp_enctypes,
     235             :                                 bool delete_all_kvno,
     236             :                                 krb5_keytab *_keytab,
     237             :                                 const char **perror_string)
     238             : {
     239         348 :         krb5_keytab keytab = NULL;
     240          26 :         krb5_error_code ret;
     241         348 :         bool found_previous = false;
     242         348 :         TALLOC_CTX *tmp_ctx = NULL;
     243         348 :         krb5_principal *principals = NULL;
     244         348 :         uint32_t num_principals = 0;
     245          26 :         char *upper_realm;
     246         348 :         const char *error_string = NULL;
     247             : 
     248         348 :         if (keytab_name == NULL) {
     249           0 :                 return ENOENT;
     250             :         }
     251             : 
     252         348 :         ret = krb5_kt_resolve(context, keytab_name, &keytab);
     253         348 :         if (ret) {
     254           0 :                 *perror_string = smb_get_krb5_error_message(context,
     255             :                                                            ret, parent_ctx);
     256           0 :                 return ret;
     257             :         }
     258             : 
     259         348 :         DEBUG(5, ("Opened keytab %s\n", keytab_name));
     260             : 
     261         348 :         tmp_ctx = talloc_new(parent_ctx);
     262         348 :         if (!tmp_ctx) {
     263           0 :                 *perror_string = talloc_strdup(parent_ctx,
     264             :                                               "Failed to allocate memory context");
     265           0 :                 ret = ENOMEM;
     266           0 :                 goto done;
     267             :         }
     268             : 
     269         348 :         upper_realm = strupper_talloc(tmp_ctx, realm);
     270         348 :         if (upper_realm == NULL) {
     271           0 :                 *perror_string = talloc_strdup(parent_ctx,
     272             :                                               "Cannot allocate memory to upper case realm");
     273           0 :                 ret = ENOMEM;
     274           0 :                 goto done;
     275             :         }
     276             : 
     277         348 :         ret = smb_krb5_create_principals_array(tmp_ctx,
     278             :                                                context,
     279             :                                                samAccountName,
     280             :                                                upper_realm,
     281             :                                                num_SPNs,
     282             :                                                SPNs,
     283             :                                                &num_principals,
     284             :                                                &principals,
     285             :                                                &error_string);
     286         348 :         if (ret != 0) {
     287           0 :                 *perror_string = talloc_asprintf(parent_ctx,
     288             :                         "Failed to load principals from ldb message: %s\n",
     289             :                         error_string);
     290           0 :                 goto done;
     291             :         }
     292             : 
     293         348 :         ret = smb_krb5_remove_obsolete_keytab_entries(tmp_ctx,
     294             :                                                       context,
     295             :                                                       keytab,
     296             :                                                       num_principals,
     297             :                                                       principals,
     298             :                                                       kvno,
     299             :                                                       &found_previous,
     300             :                                                       &error_string);
     301         348 :         if (ret != 0) {
     302           0 :                 *perror_string = talloc_asprintf(parent_ctx,
     303             :                         "Failed to remove old principals from keytab: %s\n",
     304             :                         error_string);
     305           0 :                 goto done;
     306             :         }
     307             : 
     308         348 :         if (!delete_all_kvno) {
     309             :                 /* Create a new keytab.  If during the cleanout we found
     310             :                  * entries for kvno -1, then don't try and duplicate them.
     311             :                  * Otherwise, add kvno, and kvno -1 */
     312         346 :                 if (saltPrincipal == NULL) {
     313           0 :                         *perror_string = talloc_strdup(parent_ctx,
     314             :                                                        "No saltPrincipal provided");
     315           0 :                         ret = EINVAL;
     316           0 :                         goto done;
     317             :                 }
     318             : 
     319         372 :                 ret = create_keytab(tmp_ctx,
     320             :                                     samAccountName, upper_realm, saltPrincipal,
     321             :                                     kvno, new_secret, old_secret,
     322             :                                     supp_enctypes,
     323             :                                     num_principals,
     324             :                                     principals,
     325             :                                     context, keytab,
     326         346 :                                     found_previous ? false : true,
     327             :                                     &error_string);
     328         346 :                 if (ret) {
     329           0 :                         *perror_string = talloc_steal(parent_ctx, error_string);
     330             :                 }
     331             :         }
     332             : 
     333         348 :         if (ret == 0 && _keytab != NULL) {
     334             :                 /* caller wants the keytab handle back */
     335          97 :                 *_keytab = keytab;
     336             :         }
     337             : 
     338         251 : done:
     339         348 :         keytab_principals_free(context, num_principals, principals);
     340         348 :         if (ret != 0 || _keytab == NULL) {
     341         251 :                 krb5_kt_close(context, keytab);
     342             :         }
     343         348 :         talloc_free(tmp_ctx);
     344         348 :         return ret;
     345             : }
     346             : 
     347             : /**
     348             :  * @brief Wrapper around smb_krb5_update_keytab() for creating an in-memory keytab
     349             :  *
     350             :  * @param[in] parent_ctx        Talloc memory context
     351             :  * @param[in] context           Kerberos context
     352             :  * @param[in] new_secret        New password
     353             :  * @param[in] samAccountName    User account to update
     354             :  * @param[in] realm             Kerberos realm
     355             :  * @param[in] salt_principal    Salt used for AES encryption.
     356             :  *                              Required, unless delete_all_kvno is set.
     357             :  * @param[in] kvno              Current key version number
     358             :  * @param[out] keytab           If supplied, returns the keytab
     359             :  * @param[out] keytab_name      Returns the created keytab name
     360             :  *
     361             :  * @return                      0 on success, errno on failure
     362             :  */
     363          97 : krb5_error_code smb_krb5_create_memory_keytab(TALLOC_CTX *parent_ctx,
     364             :                                 krb5_context context,
     365             :                                 const char *new_secret,
     366             :                                 const char *samAccountName,
     367             :                                 const char *realm,
     368             :                                 const char *salt_principal,
     369             :                                 int kvno,
     370             :                                 krb5_keytab *keytab,
     371             :                                 const char **keytab_name)
     372             : {
     373           0 :         krb5_error_code ret;
     374          97 :         TALLOC_CTX *mem_ctx = talloc_new(parent_ctx);
     375           0 :         const char *rand_string;
     376          97 :         const char *error_string = NULL;
     377          97 :         if (!mem_ctx) {
     378           0 :                 return ENOMEM;
     379             :         }
     380             : 
     381          97 :         rand_string = generate_random_str(mem_ctx, 16);
     382          97 :         if (!rand_string) {
     383           0 :                 talloc_free(mem_ctx);
     384           0 :                 return ENOMEM;
     385             :         }
     386             : 
     387          97 :         *keytab_name = talloc_asprintf(mem_ctx, "MEMORY:%s", rand_string);
     388          97 :         if (*keytab_name == NULL) {
     389           0 :                 talloc_free(mem_ctx);
     390           0 :                 return ENOMEM;
     391             :         }
     392             : 
     393          97 :         ret = smb_krb5_update_keytab(mem_ctx, context,
     394             :                                      *keytab_name, samAccountName, realm,
     395             :                                      NULL, 0, salt_principal, new_secret, NULL,
     396             :                                      kvno, ENC_ALL_TYPES,
     397             :                                      false, keytab, &error_string);
     398          97 :         if (ret == 0) {
     399          97 :                 talloc_steal(parent_ctx, *keytab_name);
     400             :         } else {
     401           0 :                 DEBUG(0, ("Failed to create in-memory keytab: %s\n",
     402             :                           error_string));
     403           0 :                 *keytab_name = NULL;
     404             :         }
     405          97 :         talloc_free(mem_ctx);
     406          97 :         return ret;
     407             : }

Generated by: LCOV version 1.14