LCOV - code coverage report
Current view: top level - source3/libads - kerberos_keytab.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 0 424 0.0 %
Date: 2024-06-13 04:01:37 Functions: 0 9 0.0 %

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

Generated by: LCOV version 1.13