LCOV - code coverage report
Current view: top level - source3/libads - kerberos_keytab.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 253 425 59.5 %
Date: 2021-09-23 10:06:22 Functions: 8 9 88.9 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    kerberos keytab utility library
       4             :    Copyright (C) Andrew Tridgell 2001
       5             :    Copyright (C) Remus Koos 2001
       6             :    Copyright (C) Luke Howard 2003
       7             :    Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2003
       8             :    Copyright (C) Guenther Deschner 2003
       9             :    Copyright (C) Rakesh Patel 2004
      10             :    Copyright (C) Dan Perry 2004
      11             :    Copyright (C) Jeremy Allison 2004
      12             :    Copyright (C) Gerald Carter 2006
      13             : 
      14             :    This program is free software; you can redistribute it and/or modify
      15             :    it under the terms of the GNU General Public License as published by
      16             :    the Free Software Foundation; either version 3 of the License, or
      17             :    (at your option) any later version.
      18             : 
      19             :    This program is distributed in the hope that it will be useful,
      20             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      21             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      22             :    GNU General Public License for more details.
      23             : 
      24             :    You should have received a copy of the GNU General Public License
      25             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      26             : */
      27             : 
      28             : #include "includes.h"
      29             : #include "smb_krb5.h"
      30             : #include "ads.h"
      31             : #include "secrets.h"
      32             : 
      33             : #ifdef HAVE_KRB5
      34             : 
      35             : #ifdef HAVE_ADS
      36             : 
      37             : /* This MAX_NAME_LEN is a constant defined in krb5.h */
      38             : #ifndef MAX_KEYTAB_NAME_LEN
      39             : #define MAX_KEYTAB_NAME_LEN 1100
      40             : #endif
      41             : 
      42         102 : static krb5_error_code ads_keytab_open(krb5_context context,
      43             :                                        krb5_keytab *keytab)
      44             : {
      45         102 :         char keytab_str[MAX_KEYTAB_NAME_LEN] = {0};
      46         102 :         const char *keytab_name = NULL;
      47         102 :         krb5_error_code ret = 0;
      48             : 
      49         102 :         switch (lp_kerberos_method()) {
      50           0 :         case KERBEROS_VERIFY_SYSTEM_KEYTAB:
      51             :         case KERBEROS_VERIFY_SECRETS_AND_KEYTAB:
      52           0 :                 ret = krb5_kt_default_name(context,
      53             :                                            keytab_str,
      54             :                                            sizeof(keytab_str) - 2);
      55           0 :                 if (ret != 0) {
      56           0 :                         DBG_WARNING("Failed to get default keytab name");
      57           0 :                         goto out;
      58             :                 }
      59           0 :                 keytab_name = keytab_str;
      60           0 :                 break;
      61         102 :         case KERBEROS_VERIFY_DEDICATED_KEYTAB:
      62         102 :                 keytab_name = lp_dedicated_keytab_file();
      63         102 :                 break;
      64           0 :         default:
      65           0 :                 DBG_ERR("Invalid kerberos method set (%d)\n",
      66             :                         lp_kerberos_method());
      67           0 :                 ret = KRB5_KT_BADNAME;
      68           0 :                 goto out;
      69             :         }
      70             : 
      71         102 :         if (keytab_name == NULL || keytab_name[0] == '\0') {
      72           0 :                 DBG_ERR("Invalid keytab name\n");
      73           0 :                 ret = KRB5_KT_BADNAME;
      74           0 :                 goto out;
      75             :         }
      76             : 
      77         102 :         ret = smb_krb5_kt_open(context, keytab_name, true, keytab);
      78         102 :         if (ret != 0) {
      79           0 :                 DBG_WARNING("smb_krb5_kt_open failed (%s)\n",
      80             :                             error_message(ret));
      81           0 :                 goto out;
      82             :         }
      83             : 
      84         153 : out:
      85         102 :         return ret;
      86             : }
      87             : 
      88           2 : static bool fill_default_spns(TALLOC_CTX *ctx, const char *machine_name,
      89             :                                           const char *my_fqdn, const char *spn,
      90             :                                           const char ***spns)
      91             : {
      92             :         char *psp1, *psp2;
      93             : 
      94           2 :         if (*spns == NULL) {
      95           2 :                 *spns = talloc_zero_array(ctx, const char*, 3);
      96           2 :                 if (*spns == NULL) {
      97           0 :                         return false;
      98             :                 }
      99             :         }
     100             : 
     101           2 :         psp1 = talloc_asprintf(ctx,
     102             :                                "%s/%s",
     103             :                                spn,
     104             :                                machine_name);
     105           2 :         if (psp1 == NULL) {
     106           0 :                 return false;
     107             :         }
     108             : 
     109           2 :         if (!strlower_m(&psp1[strlen(spn) + 1])) {
     110           0 :                 return false;
     111             :         }
     112           2 :         (*spns)[0] = psp1;
     113             : 
     114           2 :         psp2 = talloc_asprintf(ctx,
     115             :                                "%s/%s",
     116             :                                spn,
     117             :                                my_fqdn);
     118           2 :         if (psp2 == NULL) {
     119           0 :                 return false;
     120             :         }
     121             : 
     122           2 :         if (!strlower_m(&psp2[strlen(spn) + 1])) {
     123           0 :                 return false;
     124             :         }
     125             : 
     126           2 :         (*spns)[1] = psp2;
     127             : 
     128           2 :         return true;
     129             : }
     130             : 
     131           2 : static bool ads_set_machine_account_spns(TALLOC_CTX *ctx,
     132             :                                          ADS_STRUCT *ads,
     133             :                                          const char *service_or_spn,
     134             :                                          const char *my_fqdn)
     135             : {
     136           2 :         const char **spn_names = NULL;
     137             :         ADS_STATUS aderr;
     138           2 :         struct spn_struct* spn_struct = NULL;
     139           2 :         char *tmp = NULL;
     140             : 
     141             :         /* SPN should have '/' */
     142           2 :         tmp = strchr_m(service_or_spn, '/');
     143           2 :         if (tmp != NULL) {
     144           0 :                 spn_struct = parse_spn(ctx, service_or_spn);
     145           0 :                 if (spn_struct == NULL) {
     146           0 :                         return false;
     147             :                 }
     148             :         }
     149             : 
     150           2 :         DBG_INFO("Attempting to add/update '%s'\n", service_or_spn);
     151             : 
     152           2 :         if (spn_struct != NULL) {
     153           0 :                 spn_names = talloc_zero_array(ctx, const char*, 2);
     154           0 :                 spn_names[0] = service_or_spn;
     155             :         } else {
     156             :                 bool ok;
     157             : 
     158           2 :                 ok = fill_default_spns(ctx,
     159             :                                        lp_netbios_name(),
     160             :                                        my_fqdn,
     161             :                                        service_or_spn,
     162             :                                        &spn_names);
     163           2 :                 if (!ok) {
     164           0 :                         return false;
     165             :                 }
     166             :         }
     167           2 :         aderr = ads_add_service_principal_names(ads,
     168             :                                                 lp_netbios_name(),
     169             :                                                 spn_names);
     170           2 :         if (!ADS_ERR_OK(aderr)) {
     171           0 :                 DBG_WARNING("Failed to add service principal name.\n");
     172           0 :                 return false;
     173             :         }
     174             : 
     175           2 :         return true;
     176             : }
     177             : 
     178             : /*
     179             :  * Create kerberos principal(s) from SPN or service name.
     180             :  */
     181          88 : static bool service_or_spn_to_kerberos_princ(TALLOC_CTX *ctx,
     182             :                                              const char *service_or_spn,
     183             :                                              const char *my_fqdn,
     184             :                                              char **p_princ_s,
     185             :                                              char **p_short_princ_s)
     186             : {
     187          88 :         char *princ_s = NULL;
     188          88 :         char *short_princ_s = NULL;
     189          88 :         const char *service = service_or_spn;
     190          88 :         const char *host = my_fqdn;
     191          88 :         struct spn_struct* spn_struct = NULL;
     192          88 :         char *tmp = NULL;
     193          88 :         bool ok = true;
     194             : 
     195             :         /* SPN should have '/' */
     196          88 :         tmp = strchr_m(service_or_spn, '/');
     197          88 :         if (tmp != NULL) {
     198           8 :                 spn_struct = parse_spn(ctx, service_or_spn);
     199           8 :                 if (spn_struct == NULL) {
     200           4 :                         ok = false;
     201           4 :                         goto out;
     202             :                 }
     203             :         }
     204          84 :         if (spn_struct != NULL) {
     205           4 :                 service = spn_struct->serviceclass;
     206           4 :                 host = spn_struct->host;
     207             :         }
     208          84 :         princ_s = talloc_asprintf(ctx, "%s/%s@%s",
     209             :                                   service,
     210             :                                   host, lp_realm());
     211          84 :         if (princ_s == NULL) {
     212           0 :                 ok = false;
     213           0 :                 goto out;
     214             :         }
     215             : 
     216          84 :         if (spn_struct == NULL) {
     217          80 :                 short_princ_s = talloc_asprintf(ctx, "%s/%s@%s",
     218             :                                         service, lp_netbios_name(),
     219             :                                         lp_realm());
     220          80 :                 if (short_princ_s == NULL) {
     221           0 :                         ok = false;
     222           0 :                         goto out;
     223             :                 }
     224             :         }
     225          84 :         *p_princ_s = princ_s;
     226          84 :         *p_short_princ_s = short_princ_s;
     227          88 : out:
     228          88 :         return ok;
     229             : }
     230             : 
     231         108 : static int add_kt_entry_etypes(krb5_context context, TALLOC_CTX *tmpctx,
     232             :                                ADS_STRUCT *ads, const char *salt_princ_s,
     233             :                                krb5_keytab keytab, krb5_kvno kvno,
     234             :                                const char *srvPrinc, const char *my_fqdn,
     235             :                                krb5_data *password, bool update_ads)
     236             : {
     237         108 :         krb5_error_code ret = 0;
     238         108 :         char *princ_s = NULL;
     239         108 :         char *short_princ_s = NULL;
     240         108 :         krb5_enctype enctypes[4] = {
     241             : #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
     242             :                 ENCTYPE_AES256_CTS_HMAC_SHA1_96,
     243             : #endif
     244             : #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
     245             :                 ENCTYPE_AES128_CTS_HMAC_SHA1_96,
     246             : #endif
     247             :                 ENCTYPE_ARCFOUR_HMAC,
     248             :                 0
     249             :         };
     250             :         size_t i;
     251             : 
     252             :         /* Construct our principal */
     253         108 :         if (strchr_m(srvPrinc, '@')) {
     254             :                 /* It's a fully-named principal. */
     255           4 :                 princ_s = talloc_asprintf(tmpctx, "%s", srvPrinc);
     256           4 :                 if (!princ_s) {
     257           0 :                         ret = -1;
     258           0 :                         goto out;
     259             :                 }
     260         104 :         } else if (srvPrinc[strlen(srvPrinc)-1] == '$') {
     261             :                 /* It's the machine account, as used by smbclient clients. */
     262          16 :                 princ_s = talloc_asprintf(tmpctx, "%s@%s",
     263             :                                           srvPrinc, lp_realm());
     264          16 :                 if (!princ_s) {
     265           0 :                         ret = -1;
     266           0 :                         goto out;
     267             :                 }
     268             :         } else {
     269             :                 /* It's a normal service principal.  Add the SPN now so that we
     270             :                  * can obtain credentials for it and double-check the salt value
     271             :                  * used to generate the service's keys. */
     272             : 
     273          88 :                 if (!service_or_spn_to_kerberos_princ(tmpctx,
     274             :                                                       srvPrinc,
     275             :                                                       my_fqdn,
     276             :                                                       &princ_s,
     277             :                                                       &short_princ_s)) {
     278           4 :                         ret = -1;
     279           4 :                         goto out;
     280             :                 }
     281             : 
     282             :                 /* According to http://support.microsoft.com/kb/326985/en-us,
     283             :                    certain principal names are automatically mapped to the
     284             :                    host/... principal in the AD account.
     285             :                    So only create these in the keytab, not in AD.  --jerry */
     286             : 
     287          85 :                 if (update_ads && !strequal(srvPrinc, "cifs") &&
     288           2 :                     !strequal(srvPrinc, "host")) {
     289           2 :                         if (!ads_set_machine_account_spns(tmpctx,
     290             :                                                           ads,
     291             :                                                           srvPrinc,
     292             :                                                           my_fqdn)) {
     293           0 :                                 ret = -1;
     294           0 :                                 goto out;
     295             :                         }
     296             :                 }
     297             :         }
     298             : 
     299         416 :         for (i = 0; enctypes[i]; i++) {
     300             : 
     301             :                 /* add the fqdn principal to the keytab */
     302         312 :                 ret = smb_krb5_kt_add_entry(context,
     303             :                                             keytab,
     304             :                                             kvno,
     305             :                                             princ_s,
     306             :                                             salt_princ_s,
     307             :                                             enctypes[i],
     308             :                                             password,
     309             :                                             false,
     310             :                                             false);
     311         312 :                 if (ret) {
     312           0 :                         DBG_WARNING("Failed to add entry to keytab\n");
     313           0 :                         goto out;
     314             :                 }
     315             : 
     316             :                 /* add the short principal name if we have one */
     317         312 :                 if (short_princ_s) {
     318         240 :                         ret = smb_krb5_kt_add_entry(context,
     319             :                                                     keytab,
     320             :                                                     kvno,
     321             :                                                     short_princ_s,
     322             :                                                     salt_princ_s,
     323             :                                                     enctypes[i],
     324             :                                                     password,
     325             :                                                     false,
     326             :                                                     false);
     327         240 :                         if (ret) {
     328           0 :                                 DBG_WARNING("Failed to add short entry to keytab\n");
     329           0 :                                 goto out;
     330             :                         }
     331             :                 }
     332             :         }
     333         104 : out:
     334         108 :         return ret;
     335             : }
     336             : 
     337             : /**********************************************************************
     338             :  Adds a single service principal, i.e. 'host' to the system keytab
     339             : ***********************************************************************/
     340             : 
     341          66 : int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc, bool update_ads)
     342             : {
     343          66 :         krb5_error_code ret = 0;
     344          66 :         krb5_context context = NULL;
     345          66 :         krb5_keytab keytab = NULL;
     346             :         krb5_data password;
     347             :         krb5_kvno kvno;
     348          66 :         char *salt_princ_s = NULL;
     349          66 :         char *password_s = NULL;
     350             :         char *my_fqdn;
     351          66 :         TALLOC_CTX *tmpctx = NULL;
     352          66 :         char **hostnames_array = NULL;
     353          66 :         size_t num_hostnames = 0;
     354             : 
     355          66 :         ret = smb_krb5_init_context_common(&context);
     356          66 :         if (ret) {
     357           0 :                 DBG_ERR("kerberos init context failed (%s)\n",
     358             :                         error_message(ret));
     359           0 :                 return -1;
     360             :         }
     361             : 
     362          66 :         ret = ads_keytab_open(context, &keytab);
     363          66 :         if (ret != 0) {
     364           0 :                 goto out;
     365             :         }
     366             : 
     367             :         /* retrieve the password */
     368          66 :         if (!secrets_init()) {
     369           0 :                 DBG_WARNING("secrets_init failed\n");
     370           0 :                 ret = -1;
     371           0 :                 goto out;
     372             :         }
     373          66 :         password_s = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
     374          66 :         if (!password_s) {
     375           0 :                 DBG_WARNING("failed to fetch machine password\n");
     376           0 :                 ret = -1;
     377           0 :                 goto out;
     378             :         }
     379          66 :         ZERO_STRUCT(password);
     380          66 :         password.data = password_s;
     381          66 :         password.length = strlen(password_s);
     382             : 
     383             :         /* we need the dNSHostName value here */
     384          66 :         tmpctx = talloc_init(__location__);
     385          66 :         if (!tmpctx) {
     386           0 :                 DBG_ERR("talloc_init() failed!\n");
     387           0 :                 ret = -1;
     388           0 :                 goto out;
     389             :         }
     390             : 
     391          66 :         my_fqdn = ads_get_dnshostname(ads, tmpctx, lp_netbios_name());
     392          66 :         if (!my_fqdn) {
     393           0 :                 DBG_ERR("unable to determine machine account's dns name in "
     394             :                         "AD!\n");
     395           0 :                 ret = -1;
     396           0 :                 goto out;
     397             :         }
     398             : 
     399             :         /* make sure we have a single instance of a the computer account */
     400          66 :         if (!ads_has_samaccountname(ads, tmpctx, lp_netbios_name())) {
     401           0 :                 DBG_ERR("unable to determine machine account's short name in "
     402             :                         "AD!\n");
     403           0 :                 ret = -1;
     404           0 :                 goto out;
     405             :         }
     406             : 
     407          66 :         kvno = (krb5_kvno)ads_get_machine_kvno(ads, lp_netbios_name());
     408          66 :         if (kvno == -1) {
     409             :                 /* -1 indicates failure, everything else is OK */
     410           0 :                 DBG_WARNING("ads_get_machine_kvno failed to determine the "
     411             :                             "system's kvno.\n");
     412           0 :                 ret = -1;
     413           0 :                 goto out;
     414             :         }
     415             : 
     416          66 :         salt_princ_s = kerberos_secrets_fetch_salt_princ();
     417          66 :         if (salt_princ_s == NULL) {
     418           0 :                 DBG_WARNING("kerberos_secrets_fetch_salt_princ() failed\n");
     419           0 :                 ret = -1;
     420           0 :                 goto out;
     421             :         }
     422             : 
     423          66 :         ret = add_kt_entry_etypes(context, tmpctx, ads, salt_princ_s, keytab,
     424             :                                   kvno, srvPrinc, my_fqdn, &password,
     425             :                                   update_ads);
     426          66 :         if (ret != 0) {
     427           4 :                 goto out;
     428             :         }
     429             : 
     430          62 :         if (ADS_ERR_OK(ads_get_additional_dns_hostnames(tmpctx, ads,
     431             :                                                         lp_netbios_name(),
     432             :                                                         &hostnames_array,
     433             :                                                         &num_hostnames))) {
     434             :                 size_t i;
     435             : 
     436          56 :                 for (i = 0; i < num_hostnames; i++) {
     437             : 
     438          63 :                         ret = add_kt_entry_etypes(context, tmpctx, ads,
     439             :                                                   salt_princ_s, keytab,
     440             :                                                   kvno, srvPrinc,
     441          42 :                                                   hostnames_array[i],
     442             :                                                   &password, update_ads);
     443          42 :                         if (ret != 0) {
     444           0 :                                 goto out;
     445             :                         }
     446             :                 }
     447             :         }
     448             : 
     449          62 : out:
     450          66 :         SAFE_FREE(salt_princ_s);
     451          66 :         TALLOC_FREE(tmpctx);
     452             : 
     453          66 :         if (keytab) {
     454          66 :                 krb5_kt_close(context, keytab);
     455             :         }
     456          66 :         if (context) {
     457          66 :                 krb5_free_context(context);
     458             :         }
     459          66 :         return (int)ret;
     460             : }
     461             : 
     462             : /**********************************************************************
     463             :  Flushes all entries from the system keytab.
     464             : ***********************************************************************/
     465             : 
     466           0 : int ads_keytab_flush(ADS_STRUCT *ads)
     467             : {
     468           0 :         krb5_error_code ret = 0;
     469           0 :         krb5_context context = NULL;
     470           0 :         krb5_keytab keytab = NULL;
     471             :         krb5_kvno kvno;
     472             :         ADS_STATUS aderr;
     473             : 
     474           0 :         ret = smb_krb5_init_context_common(&context);
     475           0 :         if (ret) {
     476           0 :                 DBG_ERR("kerberos init context failed (%s)\n",
     477             :                         error_message(ret));
     478           0 :                 return ret;
     479             :         }
     480             : 
     481           0 :         ret = ads_keytab_open(context, &keytab);
     482           0 :         if (ret != 0) {
     483           0 :                 goto out;
     484             :         }
     485             : 
     486           0 :         kvno = (krb5_kvno)ads_get_machine_kvno(ads, lp_netbios_name());
     487           0 :         if (kvno == -1) {
     488             :                 /* -1 indicates a failure */
     489           0 :                 DEBUG(1, (__location__ ": Error determining the kvno.\n"));
     490           0 :                 ret = -1;
     491           0 :                 goto out;
     492             :         }
     493             : 
     494             :         /* Seek and delete old keytab entries */
     495           0 :         ret = smb_krb5_kt_seek_and_delete_old_entries(context,
     496             :                                                       keytab,
     497             :                                                       kvno,
     498             :                                                       ENCTYPE_NULL,
     499             :                                                       NULL,
     500             :                                                       NULL,
     501             :                                                       true,
     502             :                                                       false);
     503           0 :         if (ret) {
     504           0 :                 goto out;
     505             :         }
     506             : 
     507           0 :         aderr = ads_clear_service_principal_names(ads, lp_netbios_name());
     508           0 :         if (!ADS_ERR_OK(aderr)) {
     509           0 :                 DEBUG(1, (__location__ ": Error while clearing service "
     510             :                           "principal listings in LDAP.\n"));
     511           0 :                 ret = -1;
     512           0 :                 goto out;
     513             :         }
     514             : 
     515           0 : out:
     516           0 :         if (keytab) {
     517           0 :                 krb5_kt_close(context, keytab);
     518             :         }
     519           0 :         if (context) {
     520           0 :                 krb5_free_context(context);
     521             :         }
     522           0 :         return ret;
     523             : }
     524             : 
     525             : /**********************************************************************
     526             :  Adds all the required service principals to the system keytab.
     527             : ***********************************************************************/
     528             : 
     529           8 : int ads_keytab_create_default(ADS_STRUCT *ads)
     530             : {
     531           8 :         krb5_error_code ret = 0;
     532           8 :         krb5_context context = NULL;
     533           8 :         krb5_keytab keytab = NULL;
     534           8 :         krb5_kt_cursor cursor = {0};
     535           8 :         krb5_keytab_entry kt_entry = {0};
     536             :         krb5_kvno kvno;
     537           8 :         size_t found = 0;
     538             :         char *sam_account_name, *upn;
     539           8 :         char **oldEntries = NULL, *princ_s[26];
     540             :         TALLOC_CTX *frame;
     541             :         char *machine_name;
     542             :         char **spn_array;
     543             :         size_t num_spns;
     544             :         size_t i;
     545           8 :         bool ok = false;
     546             :         ADS_STATUS status;
     547             : 
     548           8 :         ZERO_STRUCT(kt_entry);
     549           8 :         ZERO_STRUCT(cursor);
     550             : 
     551           8 :         frame = talloc_stackframe();
     552           8 :         if (frame == NULL) {
     553           0 :                 ret = -1;
     554           0 :                 goto done;
     555             :         }
     556             : 
     557           8 :         status = ads_get_service_principal_names(frame,
     558             :                                                  ads,
     559             :                                                  lp_netbios_name(),
     560             :                                                  &spn_array,
     561             :                                                  &num_spns);
     562           8 :         if (!ADS_ERR_OK(status)) {
     563           0 :                 ret = -1;
     564           0 :                 goto done;
     565             :         }
     566             : 
     567          48 :         for (i = 0; i < num_spns; i++) {
     568             :                 char *srv_princ;
     569             :                 char *p;
     570             : 
     571          40 :                 srv_princ = strlower_talloc(frame, spn_array[i]);
     572          40 :                 if (srv_princ == NULL) {
     573           0 :                         ret = -1;
     574           0 :                         goto done;
     575             :                 }
     576             : 
     577          40 :                 p = strchr_m(srv_princ, '/');
     578          40 :                 if (p == NULL) {
     579           0 :                         continue;
     580             :                 }
     581          40 :                 p[0] = '\0';
     582             : 
     583             :                 /* Add the SPNs found on the DC */
     584          40 :                 ret = ads_keytab_add_entry(ads, srv_princ, false);
     585          40 :                 if (ret != 0) {
     586           0 :                         DEBUG(1, ("ads_keytab_add_entry failed while "
     587             :                                   "adding '%s' principal.\n",
     588             :                                   spn_array[i]));
     589           0 :                         goto done;
     590             :                 }
     591             :         }
     592             : 
     593             : #if 0   /* don't create the CIFS/... keytab entries since no one except smbd
     594             :            really needs them and we will fall back to verifying against
     595             :            secrets.tdb */
     596             : 
     597             :         ret = ads_keytab_add_entry(ads, "cifs", false));
     598             :         if (ret != 0 ) {
     599             :                 DEBUG(1, (__location__ ": ads_keytab_add_entry failed while "
     600             :                           "adding 'cifs'.\n"));
     601             :                 return ret;
     602             :         }
     603             : #endif
     604             : 
     605           8 :         memset(princ_s, '\0', sizeof(princ_s));
     606             : 
     607           8 :         ret = smb_krb5_init_context_common(&context);
     608           8 :         if (ret) {
     609           0 :                 DBG_ERR("kerberos init context failed (%s)\n",
     610             :                         error_message(ret));
     611           0 :                 goto done;
     612             :         }
     613             : 
     614           8 :         machine_name = talloc_strdup(frame, lp_netbios_name());
     615           8 :         if (!machine_name) {
     616           0 :                 ret = -1;
     617           0 :                 goto done;
     618             :         }
     619             : 
     620             :         /* now add the userPrincipalName and sAMAccountName entries */
     621           8 :         ok = ads_has_samaccountname(ads, frame, machine_name);
     622           8 :         if (!ok) {
     623           0 :                 DEBUG(0, (__location__ ": unable to determine machine "
     624             :                           "account's name in AD!\n"));
     625           0 :                 ret = -1;
     626           0 :                 goto done;
     627             :         }
     628             : 
     629             :         /*
     630             :          * append '$' to netbios name so 'ads_keytab_add_entry' recognises
     631             :          * it as a machine account rather than a service or Windows SPN.
     632             :          */
     633           8 :         sam_account_name = talloc_asprintf(frame, "%s$",machine_name);
     634           8 :         if (sam_account_name == NULL) {
     635           0 :                 ret = -1;
     636           0 :                 goto done;
     637             :         }
     638             :         /* upper case the sAMAccountName to make it easier for apps to
     639             :            know what case to use in the keytab file */
     640           8 :         if (!strupper_m(sam_account_name)) {
     641           0 :                 ret = -1;
     642           0 :                 goto done;
     643             :         }
     644             : 
     645           8 :         ret = ads_keytab_add_entry(ads, sam_account_name, false);
     646           8 :         if (ret != 0) {
     647           0 :                 DEBUG(1, (__location__ ": ads_keytab_add_entry() failed "
     648             :                           "while adding sAMAccountName (%s)\n",
     649             :                           sam_account_name));
     650           0 :                 goto done;
     651             :         }
     652             : 
     653             :         /* remember that not every machine account will have a upn */
     654           8 :         upn = ads_get_upn(ads, frame, machine_name);
     655           8 :         if (upn) {
     656           2 :                 ret = ads_keytab_add_entry(ads, upn, false);
     657           2 :                 if (ret != 0) {
     658           0 :                         DEBUG(1, (__location__ ": ads_keytab_add_entry() "
     659             :                                   "failed while adding UPN (%s)\n", upn));
     660           0 :                         goto done;
     661             :                 }
     662             :         }
     663             : 
     664             :         /* Now loop through the keytab and update any other existing entries */
     665           8 :         kvno = (krb5_kvno)ads_get_machine_kvno(ads, machine_name);
     666           8 :         if (kvno == (krb5_kvno)-1) {
     667           0 :                 DEBUG(1, (__location__ ": ads_get_machine_kvno() failed to "
     668             :                           "determine the system's kvno.\n"));
     669           0 :                 goto done;
     670             :         }
     671             : 
     672           8 :         DEBUG(3, (__location__ ": Searching for keytab entries to preserve "
     673             :                   "and update.\n"));
     674             : 
     675           8 :         ret = ads_keytab_open(context, &keytab);
     676           8 :         if (ret != 0) {
     677           0 :                 goto done;
     678             :         }
     679             : 
     680           8 :         ret = krb5_kt_start_seq_get(context, keytab, &cursor);
     681           8 :         if (ret != KRB5_KT_END && ret != ENOENT ) {
     682         216 :                 while ((ret = krb5_kt_next_entry(context, keytab,
     683         106 :                                                  &kt_entry, &cursor)) == 0) {
     684         204 :                         smb_krb5_kt_free_entry(context, &kt_entry);
     685         204 :                         ZERO_STRUCT(kt_entry);
     686         204 :                         found++;
     687             :                 }
     688             :         }
     689           8 :         krb5_kt_end_seq_get(context, keytab, &cursor);
     690           8 :         ZERO_STRUCT(cursor);
     691             : 
     692             :         /*
     693             :          * Hmmm. There is no "rewind" function for the keytab. This means we
     694             :          * have a race condition where someone else could add entries after
     695             :          * we've counted them. Re-open asap to minimise the race. JRA.
     696             :          */
     697           8 :         DEBUG(3, (__location__ ": Found %zd entries in the keytab.\n", found));
     698           8 :         if (!found) {
     699           0 :                 goto done;
     700             :         }
     701             : 
     702           8 :         oldEntries = talloc_zero_array(frame, char *, found + 1);
     703           8 :         if (!oldEntries) {
     704           0 :                 DEBUG(1, (__location__ ": Failed to allocate space to store "
     705             :                           "the old keytab entries (talloc failed?).\n"));
     706           0 :                 ret = -1;
     707           0 :                 goto done;
     708             :         }
     709             : 
     710           8 :         ret = krb5_kt_start_seq_get(context, keytab, &cursor);
     711           8 :         if (ret == KRB5_KT_END || ret == ENOENT) {
     712           0 :                 krb5_kt_end_seq_get(context, keytab, &cursor);
     713           0 :                 ZERO_STRUCT(cursor);
     714           0 :                 goto done;
     715             :         }
     716             : 
     717         216 :         while (krb5_kt_next_entry(context, keytab, &kt_entry, &cursor) == 0) {
     718         204 :                 if (kt_entry.vno != kvno) {
     719           0 :                         char *ktprinc = NULL;
     720             :                         char *p;
     721             : 
     722             :                         /* This returns a malloc'ed string in ktprinc. */
     723           0 :                         ret = smb_krb5_unparse_name(oldEntries, context,
     724           0 :                                                     kt_entry.principal,
     725             :                                                     &ktprinc);
     726           0 :                         if (ret) {
     727           0 :                                 DEBUG(1, (__location__
     728             :                                          ": smb_krb5_unparse_name failed "
     729             :                                          "(%s)\n", error_message(ret)));
     730           0 :                                 goto done;
     731             :                         }
     732             :                         /*
     733             :                          * From looking at the krb5 source they don't seem to
     734             :                          * take locale or mb strings into account.
     735             :                          * Maybe this is because they assume utf8 ?
     736             :                          * In this case we may need to convert from utf8 to
     737             :                          * mb charset here ? JRA.
     738             :                          */
     739           0 :                         p = strchr_m(ktprinc, '@');
     740           0 :                         if (p) {
     741           0 :                                 *p = '\0';
     742             :                         }
     743             : 
     744           0 :                         p = strchr_m(ktprinc, '/');
     745           0 :                         if (p) {
     746           0 :                                 *p = '\0';
     747             :                         }
     748           0 :                         for (i = 0; i < found; i++) {
     749           0 :                                 if (!oldEntries[i]) {
     750           0 :                                         oldEntries[i] = ktprinc;
     751           0 :                                         break;
     752             :                                 }
     753           0 :                                 if (!strcmp(oldEntries[i], ktprinc)) {
     754           0 :                                         TALLOC_FREE(ktprinc);
     755           0 :                                         break;
     756             :                                 }
     757             :                         }
     758           0 :                         if (i == found) {
     759           0 :                                 TALLOC_FREE(ktprinc);
     760             :                         }
     761             :                 }
     762         204 :                 smb_krb5_kt_free_entry(context, &kt_entry);
     763         204 :                 ZERO_STRUCT(kt_entry);
     764             :         }
     765           8 :         krb5_kt_end_seq_get(context, keytab, &cursor);
     766           8 :         ZERO_STRUCT(cursor);
     767             : 
     768           8 :         ret = 0;
     769           8 :         for (i = 0; oldEntries[i]; i++) {
     770           0 :                 ret |= ads_keytab_add_entry(ads, oldEntries[i], false);
     771           0 :                 TALLOC_FREE(oldEntries[i]);
     772             :         }
     773             : 
     774           8 : done:
     775           8 :         TALLOC_FREE(oldEntries);
     776           8 :         TALLOC_FREE(frame);
     777             : 
     778           8 :         if (context) {
     779           8 :                 if (!all_zero((uint8_t *)&kt_entry, sizeof(kt_entry))) {
     780           0 :                         smb_krb5_kt_free_entry(context, &kt_entry);
     781             :                 }
     782           8 :                 if (!all_zero((uint8_t *)&cursor, sizeof(cursor)) && keytab) {
     783           0 :                         krb5_kt_end_seq_get(context, keytab, &cursor);
     784             :                 }
     785           8 :                 if (keytab) {
     786           8 :                         krb5_kt_close(context, keytab);
     787             :                 }
     788           8 :                 krb5_free_context(context);
     789             :         }
     790           8 :         return ret;
     791             : }
     792             : 
     793             : #endif /* HAVE_ADS */
     794             : 
     795             : /**********************************************************************
     796             :  List system keytab.
     797             : ***********************************************************************/
     798             : 
     799          30 : int ads_keytab_list(const char *keytab_name)
     800             : {
     801          30 :         krb5_error_code ret = 0;
     802          30 :         krb5_context context = NULL;
     803          30 :         krb5_keytab keytab = NULL;
     804             :         krb5_kt_cursor cursor;
     805             :         krb5_keytab_entry kt_entry;
     806             : 
     807          30 :         ZERO_STRUCT(kt_entry);
     808          30 :         ZERO_STRUCT(cursor);
     809             : 
     810          30 :         ret = smb_krb5_init_context_common(&context);
     811          30 :         if (ret) {
     812           0 :                 DBG_ERR("kerberos init context failed (%s)\n",
     813             :                         error_message(ret));
     814           0 :                 return ret;
     815             :         }
     816             : 
     817          30 :         if (keytab_name == NULL) {
     818             : #ifdef HAVE_ADS
     819          28 :                 ret = ads_keytab_open(context, &keytab);
     820             : #else
     821           0 :                 ret = ENOENT;
     822             : #endif
     823             :         } else {
     824           2 :                 ret = smb_krb5_kt_open(context, keytab_name, False, &keytab);
     825             :         }
     826          30 :         if (ret) {
     827           0 :                 DEBUG(1, ("smb_krb5_kt_open failed (%s)\n",
     828             :                           error_message(ret)));
     829           0 :                 goto out;
     830             :         }
     831             : 
     832          30 :         ret = krb5_kt_start_seq_get(context, keytab, &cursor);
     833          30 :         if (ret) {
     834           0 :                 ZERO_STRUCT(cursor);
     835           0 :                 goto out;
     836             :         }
     837             : 
     838          30 :         printf("Vno  Type                                        Principal\n");
     839             : 
     840         369 :         while (krb5_kt_next_entry(context, keytab, &kt_entry, &cursor) == 0) {
     841             : 
     842         678 :                 char *princ_s = NULL;
     843         678 :                 char *etype_s = NULL;
     844         678 :                 krb5_enctype enctype = 0;
     845             : 
     846         678 :                 ret = smb_krb5_unparse_name(talloc_tos(), context,
     847         678 :                                             kt_entry.principal, &princ_s);
     848         678 :                 if (ret) {
     849           0 :                         goto out;
     850             :                 }
     851             : 
     852         678 :                 enctype = smb_krb5_kt_get_enctype_from_entry(&kt_entry);
     853             : 
     854         678 :                 ret = smb_krb5_enctype_to_string(context, enctype, &etype_s);
     855         678 :                 if (ret &&
     856           0 :                     (asprintf(&etype_s, "UNKNOWN: %d", enctype) == -1)) {
     857           0 :                         TALLOC_FREE(princ_s);
     858           0 :                         goto out;
     859             :                 }
     860             : 
     861         678 :                 printf("%3d  %-43s %s\n", kt_entry.vno, etype_s, princ_s);
     862             : 
     863         678 :                 TALLOC_FREE(princ_s);
     864         678 :                 SAFE_FREE(etype_s);
     865             : 
     866         678 :                 ret = smb_krb5_kt_free_entry(context, &kt_entry);
     867         678 :                 if (ret) {
     868           0 :                         goto out;
     869             :                 }
     870             :         }
     871             : 
     872          30 :         ret = krb5_kt_end_seq_get(context, keytab, &cursor);
     873          30 :         if (ret) {
     874           0 :                 goto out;
     875             :         }
     876             : 
     877             :         /* Ensure we don't double free. */
     878          30 :         ZERO_STRUCT(kt_entry);
     879          30 :         ZERO_STRUCT(cursor);
     880          30 : out:
     881             : 
     882          30 :         if (!all_zero((uint8_t *)&kt_entry, sizeof(kt_entry))) {
     883           0 :                 smb_krb5_kt_free_entry(context, &kt_entry);
     884             :         }
     885          30 :         if (!all_zero((uint8_t *)&cursor, sizeof(cursor)) && keytab) {
     886           0 :                 krb5_kt_end_seq_get(context, keytab, &cursor);
     887             :         }
     888             : 
     889          30 :         if (keytab) {
     890          30 :                 krb5_kt_close(context, keytab);
     891             :         }
     892          30 :         if (context) {
     893          30 :                 krb5_free_context(context);
     894             :         }
     895          30 :         return ret;
     896             : }
     897             : 
     898             : #endif /* HAVE_KRB5 */

Generated by: LCOV version 1.13