LCOV - code coverage report
Current view: top level - source4/auth/kerberos - kerberos_util.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 176 241 73.0 %
Date: 2024-06-13 04:01:37 Functions: 9 9 100.0 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    Kerberos utility functions for GENSEC
       5             :    
       6             :    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             :    
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    
      19             :    You should have received a copy of the GNU General Public License
      20             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      21             : */
      22             : 
      23             : #include "includes.h"
      24             : #include "system/kerberos.h"
      25             : #include "auth/kerberos/kerberos.h"
      26             : #include "auth/credentials/credentials.h"
      27             : #include "auth/credentials/credentials_krb5.h"
      28             : #include "auth/kerberos/kerberos_credentials.h"
      29             : #include "auth/kerberos/kerberos_util.h"
      30             : 
      31             : struct principal_container {
      32             :         struct smb_krb5_context *smb_krb5_context;
      33             :         krb5_principal principal;
      34             :         const char *string_form; /* Optional */
      35             : };
      36             : 
      37       40108 : static krb5_error_code free_principal(struct principal_container *pc)
      38             : {
      39             :         /* current heimdal - 0.6.3, which we need anyway, fixes segfaults here */
      40       40108 :         krb5_free_principal(pc->smb_krb5_context->krb5_context, pc->principal);
      41             : 
      42       40108 :         return 0;
      43             : }
      44             : 
      45             : 
      46       47885 : static krb5_error_code parse_principal(TALLOC_CTX *parent_ctx,
      47             :                                        const char *princ_string,
      48             :                                        struct smb_krb5_context *smb_krb5_context,
      49             :                                        krb5_principal *princ,
      50             :                                        const char **error_string)
      51             : {
      52             :         int ret;
      53             :         struct principal_container *mem_ctx;
      54       47885 :         if (princ_string == NULL) {
      55        7777 :                  *princ = NULL;
      56        7777 :                  return 0;
      57             :         }
      58             : 
      59       40108 :         ret = krb5_parse_name(smb_krb5_context->krb5_context,
      60             :                               princ_string, princ);
      61             : 
      62       40108 :         if (ret) {
      63           0 :                 (*error_string) = smb_get_krb5_error_message(
      64             :                                                 smb_krb5_context->krb5_context,
      65             :                                                 ret, parent_ctx);
      66           0 :                 return ret;
      67             :         }
      68             : 
      69       40108 :         mem_ctx = talloc(parent_ctx, struct principal_container);
      70       40108 :         if (!mem_ctx) {
      71           0 :                 (*error_string) = error_message(ENOMEM);
      72           0 :                 return ENOMEM;
      73             :         }
      74             : 
      75             :         /* This song-and-dance effectivly puts the principal
      76             :          * into talloc, so we can't loose it. */
      77       40108 :         mem_ctx->smb_krb5_context = talloc_reference(mem_ctx,
      78             :                                                      smb_krb5_context);
      79       40108 :         mem_ctx->principal = *princ;
      80       40108 :         talloc_set_destructor(mem_ctx, free_principal);
      81       40108 :         return 0;
      82             : }
      83             : 
      84             : /* Obtain the principal set on this context.  Requires a
      85             :  * smb_krb5_context because we are doing krb5 principal parsing with
      86             :  * the library routines.  The returned princ is placed in the talloc
      87             :  * system by means of a destructor (do *not* free). */
      88             : 
      89       40085 : krb5_error_code principal_from_credentials(TALLOC_CTX *parent_ctx,
      90             :                                 struct cli_credentials *credentials,
      91             :                                 struct smb_krb5_context *smb_krb5_context,
      92             :                                 krb5_principal *princ,
      93             :                                 enum credentials_obtained *obtained,
      94             :                                 const char **error_string)
      95             : {
      96             :         krb5_error_code ret;
      97             :         const char *princ_string;
      98       40085 :         TALLOC_CTX *mem_ctx = talloc_new(parent_ctx);
      99       40085 :         *obtained = CRED_UNINITIALISED;
     100             : 
     101       40085 :         if (!mem_ctx) {
     102           0 :                 (*error_string) = error_message(ENOMEM);
     103           0 :                 return ENOMEM;
     104             :         }
     105       40085 :         princ_string = cli_credentials_get_principal_and_obtained(credentials,
     106             :                                                                   mem_ctx,
     107             :                                                                   obtained);
     108       40085 :         if (!princ_string) {
     109           6 :                 *princ = NULL;
     110           6 :                 return 0;
     111             :         }
     112             : 
     113       40079 :         ret = parse_principal(parent_ctx, princ_string,
     114             :                               smb_krb5_context, princ, error_string);
     115       40079 :         talloc_free(mem_ctx);
     116       40079 :         return ret;
     117             : }
     118             : 
     119             : /* Obtain the principal set on this context.  Requires a
     120             :  * smb_krb5_context because we are doing krb5 principal parsing with
     121             :  * the library routines.  The returned princ is placed in the talloc
     122             :  * system by means of a destructor (do *not* free). */
     123             : 
     124        7806 : static krb5_error_code impersonate_principal_from_credentials(
     125             :                                 TALLOC_CTX *parent_ctx,
     126             :                                 struct cli_credentials *credentials,
     127             :                                 struct smb_krb5_context *smb_krb5_context,
     128             :                                 krb5_principal *princ,
     129             :                                 const char **error_string)
     130             : {
     131        7806 :         return parse_principal(parent_ctx,
     132             :                         cli_credentials_get_impersonate_principal(credentials),
     133             :                         smb_krb5_context, princ, error_string);
     134             : }
     135             : 
     136         241 : krb5_error_code smb_krb5_create_principals_array(TALLOC_CTX *mem_ctx,
     137             :                                                  krb5_context context,
     138             :                                                  const char *account_name,
     139             :                                                  const char *realm,
     140             :                                                  uint32_t num_spns,
     141             :                                                  const char *spns[],
     142             :                                                  uint32_t *pnum_principals,
     143             :                                                  krb5_principal **pprincipals,
     144             :                                                  const char **error_string)
     145             : {
     146             :         krb5_error_code code;
     147             :         TALLOC_CTX *tmp_ctx;
     148         241 :         uint32_t num_principals = 0;
     149             :         krb5_principal *principals;
     150             :         uint32_t i;
     151             : 
     152         241 :         tmp_ctx = talloc_new(mem_ctx);
     153         241 :         if (tmp_ctx == NULL) {
     154           0 :                 *error_string = "Cannot allocate tmp_ctx";
     155           0 :                 return ENOMEM;
     156             :         }
     157             : 
     158         241 :         if (realm == NULL) {
     159           0 :                 *error_string = "Cannot create principal without a realm";
     160           0 :                 code = EINVAL;
     161           0 :                 goto done;
     162             :         }
     163             : 
     164         241 :         if (account_name == NULL && (num_spns == 0 || spns == NULL)) {
     165           0 :                 *error_string = "Cannot create principal without an account or SPN";
     166           0 :                 code = EINVAL;
     167           0 :                 goto done;
     168             :         }
     169             : 
     170         241 :         if (account_name != NULL && account_name[0] != '\0') {
     171         241 :                 num_principals++;
     172             :         }
     173         241 :         num_principals += num_spns;
     174             : 
     175         241 :         principals = talloc_zero_array(tmp_ctx,
     176             :                                        krb5_principal,
     177             :                                        num_principals);
     178         241 :         if (principals == NULL) {
     179           0 :                 *error_string = "Cannot allocate principals";
     180           0 :                 code = ENOMEM;
     181           0 :                 goto done;
     182             :         }
     183             : 
     184         570 :         for (i = 0; i < num_spns; i++) {
     185         329 :                 code = krb5_parse_name(context, spns[i], &(principals[i]));
     186         329 :                 if (code != 0) {
     187           0 :                         *error_string = smb_get_krb5_error_message(context,
     188             :                                                                    code,
     189             :                                                                    mem_ctx);
     190           0 :                         goto done;
     191             :                 }
     192             :         }
     193             : 
     194         241 :         if (account_name != NULL && account_name[0] != '\0') {
     195         241 :                 code = smb_krb5_make_principal(context,
     196         241 :                                                &(principals[i]),
     197             :                                                realm,
     198             :                                                account_name,
     199             :                                                NULL);
     200         241 :                 if (code != 0) {
     201           0 :                         *error_string = smb_get_krb5_error_message(context,
     202             :                                                                    code,
     203             :                                                                    mem_ctx);
     204           0 :                         goto done;
     205             :                 }
     206             :         }
     207             : 
     208         241 :         if (pnum_principals != NULL) {
     209         241 :                 *pnum_principals = num_principals;
     210             : 
     211         241 :                 if (pprincipals != NULL) {
     212         241 :                         *pprincipals = talloc_steal(mem_ctx, principals);
     213             :                 }
     214             :         }
     215             : 
     216         241 :         code = 0;
     217         241 : done:
     218         241 :         talloc_free(tmp_ctx);
     219         241 :         return code;
     220             : }
     221             : 
     222             : /**
     223             :  * Return a freshly allocated ccache (destroyed by destructor on child
     224             :  * of parent_ctx), for a given set of client credentials 
     225             :  */
     226             : 
     227        7808 :  krb5_error_code kinit_to_ccache(TALLOC_CTX *parent_ctx,
     228             :                                  struct cli_credentials *credentials,
     229             :                                  struct smb_krb5_context *smb_krb5_context,
     230             :                                  struct tevent_context *event_ctx,
     231             :                                  krb5_ccache ccache,
     232             :                                  enum credentials_obtained *obtained,
     233             :                                  const char **error_string)
     234             : {
     235             :         krb5_error_code ret;
     236             :         const char *password;
     237             :         const char *self_service;
     238             :         const char *target_service;
     239        7808 :         time_t kdc_time = 0;
     240             :         krb5_principal princ;
     241             :         krb5_principal impersonate_principal;
     242             :         int tries;
     243        7808 :         TALLOC_CTX *mem_ctx = talloc_new(parent_ctx);
     244             :         krb5_get_init_creds_opt *krb_options;
     245             : 
     246        7808 :         if (!mem_ctx) {
     247           0 :                 (*error_string) = strerror(ENOMEM);
     248           0 :                 return ENOMEM;
     249             :         }
     250             : 
     251        7808 :         ret = principal_from_credentials(mem_ctx, credentials, smb_krb5_context, &princ, obtained, error_string);
     252        7808 :         if (ret) {
     253           0 :                 talloc_free(mem_ctx);
     254           0 :                 return ret;
     255             :         }
     256             : 
     257        7808 :         if (princ == NULL) {
     258           2 :                 (*error_string) = talloc_asprintf(credentials, "principal, username or realm was not specified in the credentials");
     259           2 :                 talloc_free(mem_ctx);
     260           2 :                 return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
     261             :         }
     262             : 
     263        7806 :         ret = impersonate_principal_from_credentials(mem_ctx, credentials, smb_krb5_context, &impersonate_principal, error_string);
     264        7806 :         if (ret) {
     265           0 :                 talloc_free(mem_ctx);
     266           0 :                 return ret;
     267             :         }
     268             : 
     269        7806 :         self_service = cli_credentials_get_self_service(credentials);
     270        7806 :         target_service = cli_credentials_get_target_service(credentials);
     271             : 
     272        7806 :         password = cli_credentials_get_password(credentials);
     273             : 
     274             :         /* setup the krb5 options we want */
     275        7806 :         if ((ret = krb5_get_init_creds_opt_alloc(smb_krb5_context->krb5_context, &krb_options))) {
     276           0 :                 (*error_string) = talloc_asprintf(credentials, "krb5_get_init_creds_opt_alloc failed (%s)\n",
     277             :                                                   smb_get_krb5_error_message(smb_krb5_context->krb5_context,
     278             :                                                                              ret, mem_ctx));
     279           0 :                 talloc_free(mem_ctx);
     280           0 :                 return ret;
     281             :         }
     282             : 
     283             : #ifdef SAMBA4_USES_HEIMDAL /* Disable for now MIT reads defaults when needed */
     284             :         /* get the defaults */
     285        6955 :         krb5_get_init_creds_opt_set_default_flags(smb_krb5_context->krb5_context, NULL, NULL, krb_options);
     286             : #endif
     287             :         /* set if we want a forwardable ticket */
     288        7806 :         switch (cli_credentials_get_krb_forwardable(credentials)) {
     289        7790 :         case CRED_AUTO_KRB_FORWARDABLE:
     290        7790 :                 break;
     291          16 :         case CRED_NO_KRB_FORWARDABLE:
     292          16 :                 krb5_get_init_creds_opt_set_forwardable(krb_options, FALSE);
     293          16 :                 break;
     294           0 :         case CRED_FORCE_KRB_FORWARDABLE:
     295           0 :                 krb5_get_init_creds_opt_set_forwardable(krb_options, TRUE);
     296           0 :                 break;
     297             :         }
     298             : 
     299             : #ifdef SAMBA4_USES_HEIMDAL /* FIXME: MIT does not have this yet */
     300             :         /*
     301             :          * In order to work against windows KDCs even if we use
     302             :          * the netbios domain name as realm, we need to add the following
     303             :          * flags:
     304             :          * KRB5_INIT_CREDS_NO_C_CANON_CHECK;
     305             :          * KRB5_INIT_CREDS_NO_C_NO_EKU_CHECK;
     306             :          *
     307             :          * On MIT: Set pkinit_eku_checking to none
     308             :          */
     309        6955 :         krb5_get_init_creds_opt_set_win2k(smb_krb5_context->krb5_context,
     310             :                                           krb_options, true);
     311        6955 :         krb5_get_init_creds_opt_set_canonicalize(smb_krb5_context->krb5_context,
     312             :                                                  krb_options, true);
     313             : #else /* MIT */
     314         851 :         krb5_get_init_creds_opt_set_canonicalize(krb_options, true);
     315             : #endif
     316             : 
     317        7806 :         tries = 2;
     318       14761 :         while (tries--) {
     319             : #ifdef SAMBA4_USES_HEIMDAL
     320             :                 struct tevent_context *previous_ev;
     321             :                 /* Do this every time, in case we have weird recursive issues here */
     322        6955 :                 ret = smb_krb5_context_set_event_ctx(smb_krb5_context, event_ctx, &previous_ev);
     323        6955 :                 if (ret) {
     324           0 :                         talloc_free(mem_ctx);
     325           1 :                         return ret;
     326             :                 }
     327             : #endif
     328        7806 :                 if (password) {
     329        7798 :                         if (impersonate_principal) {
     330          29 :                                 ret = smb_krb5_kinit_s4u2_ccache(smb_krb5_context->krb5_context,
     331             :                                                                  ccache,
     332             :                                                                  princ,
     333             :                                                                  password,
     334             :                                                                  impersonate_principal,
     335             :                                                                  self_service,
     336             :                                                                  target_service,
     337             :                                                                  krb_options,
     338             :                                                                  NULL,
     339             :                                                                  &kdc_time);
     340             :                         } else {
     341        7769 :                                 ret = smb_krb5_kinit_password_ccache(smb_krb5_context->krb5_context,
     342             :                                                                      ccache,
     343             :                                                                      princ,
     344             :                                                                      password,
     345             :                                                                      target_service,
     346             :                                                                      krb_options,
     347             :                                                                      NULL,
     348             :                                                                      &kdc_time);
     349             :                         }
     350           8 :                 } else if (impersonate_principal) {
     351           0 :                         talloc_free(mem_ctx);
     352           0 :                         (*error_string) = "INTERNAL error: Cannot impersonate principal with just a keyblock.  A password must be specified in the credentials";
     353           0 :                         return EINVAL;
     354             :                 } else {
     355             :                         /* No password available, try to use a keyblock instead */
     356             :                         
     357             :                         krb5_keyblock keyblock;
     358             :                         const struct samr_Password *mach_pwd;
     359           8 :                         mach_pwd = cli_credentials_get_nt_hash(credentials, mem_ctx);
     360           8 :                         if (!mach_pwd) {
     361           2 :                                 talloc_free(mem_ctx);
     362           2 :                                 (*error_string) = "kinit_to_ccache: No password available for kinit\n";
     363           2 :                                 krb5_get_init_creds_opt_free(smb_krb5_context->krb5_context, krb_options);
     364             : #ifdef SAMBA4_USES_HEIMDAL
     365           1 :                                 smb_krb5_context_remove_event_ctx(smb_krb5_context, previous_ev, event_ctx);
     366             : #endif
     367           2 :                                 return EINVAL;
     368             :                         }
     369           6 :                         ret = smb_krb5_keyblock_init_contents(smb_krb5_context->krb5_context,
     370             :                                                  ENCTYPE_ARCFOUR_HMAC,
     371           6 :                                                  mach_pwd->hash, sizeof(mach_pwd->hash), 
     372             :                                                  &keyblock);
     373             :                         
     374           6 :                         if (ret == 0) {
     375           6 :                                 ret = smb_krb5_kinit_keyblock_ccache(smb_krb5_context->krb5_context,
     376             :                                                                      ccache,
     377             :                                                                      princ,
     378             :                                                                      &keyblock,
     379             :                                                                      target_service,
     380             :                                                                      krb_options,
     381             :                                                                      NULL,
     382             :                                                                      &kdc_time);
     383           6 :                                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &keyblock);
     384             :                         }
     385             :                 }
     386             : 
     387             : #ifdef SAMBA4_USES_HEIMDAL
     388        6954 :                 smb_krb5_context_remove_event_ctx(smb_krb5_context, previous_ev, event_ctx);
     389             : #endif
     390             : 
     391        7804 :                 if (ret == KRB5KRB_AP_ERR_SKEW || ret == KRB5_KDCREP_SKEW) {
     392             :                         /* Perhaps we have been given an invalid skew, so try again without it */
     393           0 :                         time_t t = time(NULL);
     394           0 :                         krb5_set_real_time(smb_krb5_context->krb5_context, t, 0);
     395             :                 } else {
     396             :                         /* not a skew problem */
     397             :                         break;
     398             :                 }
     399             :         }
     400             : 
     401        7804 :         krb5_get_init_creds_opt_free(smb_krb5_context->krb5_context, krb_options);
     402             : 
     403        7804 :         if (ret == KRB5KRB_AP_ERR_SKEW || ret == KRB5_KDCREP_SKEW) {
     404           0 :                 (*error_string) = talloc_asprintf(credentials, "kinit for %s failed (%s)\n",
     405             :                                                   cli_credentials_get_principal(credentials, mem_ctx),
     406             :                                                   smb_get_krb5_error_message(smb_krb5_context->krb5_context,
     407             :                                                                              ret, mem_ctx));
     408           0 :                 talloc_free(mem_ctx);
     409           0 :                 return ret;
     410             :         }
     411             : 
     412             :         /* cope with ticket being in the future due to clock skew */
     413        7804 :         if ((unsigned)kdc_time > time(NULL)) {
     414           0 :                 time_t t = time(NULL);
     415           0 :                 int time_offset =(unsigned)kdc_time-t;
     416           0 :                 DEBUG(4,("Advancing clock by %d seconds to cope with clock skew\n", time_offset));
     417           0 :                 krb5_set_real_time(smb_krb5_context->krb5_context, t + time_offset + 1, 0);
     418             :         }
     419             :         
     420        7804 :         if (ret == KRB5KDC_ERR_PREAUTH_FAILED && cli_credentials_wrong_password(credentials)) {
     421           0 :                 ret = kinit_to_ccache(parent_ctx,
     422             :                                       credentials,
     423             :                                       smb_krb5_context,
     424             :                                       event_ctx,
     425             :                                       ccache, obtained,
     426             :                                       error_string);
     427             :         }
     428             : 
     429        7804 :         if (ret) {
     430         381 :                 (*error_string) = talloc_asprintf(credentials, "kinit for %s failed (%s)\n",
     431             :                                                   cli_credentials_get_principal(credentials, mem_ctx),
     432             :                                                   smb_get_krb5_error_message(smb_krb5_context->krb5_context,
     433             :                                                                              ret, mem_ctx));
     434         381 :                 talloc_free(mem_ctx);
     435         381 :                 return ret;
     436             :         }
     437             : 
     438        7423 :         DEBUG(10,("kinit for %s succeeded\n",
     439             :                 cli_credentials_get_principal(credentials, mem_ctx)));
     440             : 
     441             : 
     442        7423 :         talloc_free(mem_ctx);
     443        7423 :         return 0;
     444             : }
     445             : 
     446       41053 : static krb5_error_code free_keytab_container(struct keytab_container *ktc)
     447             : {
     448       41053 :         return krb5_kt_close(ktc->smb_krb5_context->krb5_context, ktc->keytab);
     449             : }
     450             : 
     451       41000 : krb5_error_code smb_krb5_get_keytab_container(TALLOC_CTX *mem_ctx,
     452             :                                 struct smb_krb5_context *smb_krb5_context,
     453             :                                 krb5_keytab opt_keytab,
     454             :                                 const char *keytab_name,
     455             :                                 struct keytab_container **ktc)
     456             : {
     457             :         krb5_keytab keytab;
     458             :         krb5_error_code ret;
     459             : 
     460       41000 :         if (opt_keytab) {
     461          67 :                 keytab = opt_keytab;
     462             :         } else {
     463       40933 :                 ret = krb5_kt_resolve(smb_krb5_context->krb5_context,
     464             :                                                 keytab_name, &keytab);
     465       40933 :                 if (ret) {
     466           0 :                         DEBUG(1,("failed to open krb5 keytab: %s\n",
     467             :                                  smb_get_krb5_error_message(
     468             :                                         smb_krb5_context->krb5_context,
     469             :                                         ret, mem_ctx)));
     470           0 :                         return ret;
     471             :                 }
     472             :         }
     473             : 
     474       41000 :         *ktc = talloc(mem_ctx, struct keytab_container);
     475       41000 :         if (!*ktc) {
     476           0 :                 return ENOMEM;
     477             :         }
     478             : 
     479       41000 :         (*ktc)->smb_krb5_context = talloc_reference(*ktc, smb_krb5_context);
     480       41000 :         (*ktc)->keytab = keytab;
     481       41000 :         (*ktc)->password_based = false;
     482       41000 :         talloc_set_destructor(*ktc, free_keytab_container);
     483             : 
     484       41000 :         return 0;
     485             : }
     486             : 
     487             : /*
     488             :  * Walk the keytab, looking for entries of this principal name,
     489             :  * with KVNO other than current kvno -1.
     490             :  *
     491             :  * These entries are now stale,
     492             :  * we only keep the current and previous entries around.
     493             :  *
     494             :  * Inspired by the code in Samba3 for 'use kerberos keytab'.
     495             :  */
     496         241 : krb5_error_code smb_krb5_remove_obsolete_keytab_entries(TALLOC_CTX *mem_ctx,
     497             :                                                         krb5_context context,
     498             :                                                         krb5_keytab keytab,
     499             :                                                         uint32_t num_principals,
     500             :                                                         krb5_principal *principals,
     501             :                                                         krb5_kvno kvno,
     502             :                                                         bool *found_previous,
     503             :                                                         const char **error_string)
     504             : {
     505             :         TALLOC_CTX *tmp_ctx;
     506             :         krb5_error_code code;
     507             :         krb5_kt_cursor cursor;
     508             : 
     509         241 :         tmp_ctx = talloc_new(mem_ctx);
     510         241 :         if (tmp_ctx == NULL) {
     511           0 :                 *error_string = "Cannot allocate tmp_ctx";
     512           0 :                 return ENOMEM;
     513             :         }
     514             : 
     515         241 :         *found_previous = true;
     516             : 
     517         241 :         code = krb5_kt_start_seq_get(context, keytab, &cursor);
     518         241 :         switch (code) {
     519         107 :         case 0:
     520         107 :                 break;
     521             : #ifdef HEIM_ERR_OPNOTSUPP
     522             :         case HEIM_ERR_OPNOTSUPP:
     523             : #endif
     524         134 :         case ENOENT:
     525             :         case KRB5_KT_END:
     526             :                 /* no point enumerating if there isn't anything here */
     527         134 :                 code = 0;
     528         134 :                 goto done;
     529           0 :         default:
     530           0 :                 *error_string = talloc_asprintf(mem_ctx,
     531             :                                                 "failed to open keytab for read of old entries: %s\n",
     532             :                                                 smb_get_krb5_error_message(context, code, mem_ctx));
     533           0 :                 goto done;
     534             :         }
     535             : 
     536        1452 :         do {
     537        1559 :                 krb5_kvno old_kvno = kvno - 1;
     538             :                 krb5_keytab_entry entry;
     539        1559 :                 bool matched = false;
     540             :                 uint32_t i;
     541             : 
     542        1559 :                 code = krb5_kt_next_entry(context, keytab, &entry, &cursor);
     543        1559 :                 if (code) {
     544         195 :                         break;
     545             :                 }
     546             : 
     547        3227 :                 for (i = 0; i < num_principals; i++) {
     548             :                         krb5_boolean ok;
     549             : 
     550        2978 :                         ok = smb_krb5_kt_compare(context,
     551             :                                                 &entry,
     552        2978 :                                                 principals[i],
     553             :                                                 0,
     554             :                                                 0);
     555        2978 :                         if (ok) {
     556        1203 :                                 matched = true;
     557        1203 :                                 break;
     558             :                         }
     559             :                 }
     560             : 
     561        1452 :                 if (!matched) {
     562             :                         /*
     563             :                          * Free the entry, it wasn't the one we were looking
     564             :                          * for anyway
     565             :                          */
     566         249 :                         krb5_kt_free_entry(context, &entry);
     567             :                         /* Make sure we do not double free */
     568         249 :                         ZERO_STRUCT(entry);
     569         249 :                         continue;
     570             :                 }
     571             : 
     572             :                 /*
     573             :                  * Delete it, if it is not kvno - 1.
     574             :                  *
     575             :                  * Some keytab files store the kvno only in 8bits. Limit the
     576             :                  * compare to 8bits, so that we don't miss old keys and delete
     577             :                  * them.
     578             :                  */
     579        1203 :                 if ((entry.vno & 0xff) != (old_kvno & 0xff)) {
     580             :                         krb5_error_code rc;
     581             : 
     582             :                         /* Release the enumeration.  We are going to
     583             :                          * have to start this from the top again,
     584             :                          * because deletes during enumeration may not
     585             :                          * always be consistent.
     586             :                          *
     587             :                          * Also, the enumeration locks a FILE: keytab
     588             :                          */
     589         230 :                         krb5_kt_end_seq_get(context, keytab, &cursor);
     590             : 
     591         230 :                         code = krb5_kt_remove_entry(context, keytab, &entry);
     592         230 :                         krb5_kt_free_entry(context, &entry);
     593             : 
     594             :                         /* Make sure we do not double free */
     595         230 :                         ZERO_STRUCT(entry);
     596             : 
     597             :                         /* Deleted: Restart from the top */
     598         230 :                         rc = krb5_kt_start_seq_get(context, keytab, &cursor);
     599         230 :                         if (rc != 0) {
     600           0 :                                 krb5_kt_free_entry(context, &entry);
     601             : 
     602             :                                 /* Make sure we do not double free */
     603           0 :                                 ZERO_STRUCT(entry);
     604             : 
     605           0 :                                 DEBUG(1, ("failed to restart enumeration of keytab: %s\n",
     606             :                                           smb_get_krb5_error_message(context,
     607             :                                                                      code,
     608             :                                                                      tmp_ctx)));
     609             : 
     610           0 :                                 talloc_free(tmp_ctx);
     611           0 :                                 return rc;
     612             :                         }
     613             : 
     614         230 :                         if (code != 0) {
     615           0 :                                 break;
     616             :                         }
     617             : 
     618             :                 } else {
     619         973 :                         *found_previous = true;
     620             :                 }
     621             : 
     622             :                 /* Free the entry, we don't need it any more */
     623        1203 :                 krb5_kt_free_entry(context, &entry);
     624             :                 /* Make sure we do not double free */
     625        1203 :                 ZERO_STRUCT(entry);
     626        1452 :         } while (code == 0);
     627             : 
     628         107 :         krb5_kt_end_seq_get(context, keytab, &cursor);
     629             : 
     630         107 :         switch (code) {
     631           0 :         case 0:
     632           0 :                 break;
     633         107 :         case ENOENT:
     634             :         case KRB5_KT_END:
     635         107 :                 break;
     636           0 :         default:
     637           0 :                 *error_string = talloc_asprintf(mem_ctx,
     638             :                                                 "failed in deleting old entries for principal: %s\n",
     639             :                                                 smb_get_krb5_error_message(context,
     640             :                                                                            code,
     641             :                                                                            mem_ctx));
     642             :         }
     643             : 
     644         107 :         code = 0;
     645         241 : done:
     646         241 :         talloc_free(tmp_ctx);
     647         241 :         return code;
     648             : }

Generated by: LCOV version 1.13