root/source4/auth/kerberos/kerberos_util.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. free_principal
  2. salt_principal_from_credentials
  3. principal_from_credentials
  4. kinit_to_ccache
  5. free_keytab
  6. smb_krb5_open_keytab
  7. keytab_add_keys
  8. create_keytab
  9. remove_old_entries
  10. smb_krb5_update_keytab
  11. smb_krb5_create_memory_keytab

   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_proto.h"
  28 #include "auth/credentials/credentials_krb5.h"
  29 
  30 struct principal_container {
  31         struct smb_krb5_context *smb_krb5_context;
  32         krb5_principal principal;
  33 };
  34 
  35 static krb5_error_code free_principal(struct principal_container *pc)
     /* [<][>][^][v][top][bottom][index][help] */
  36 {
  37         /* current heimdal - 0.6.3, which we need anyway, fixes segfaults here */
  38         krb5_free_principal(pc->smb_krb5_context->krb5_context, pc->principal);
  39 
  40         return 0;
  41 }
  42 
  43 static krb5_error_code salt_principal_from_credentials(TALLOC_CTX *parent_ctx, 
     /* [<][>][^][v][top][bottom][index][help] */
  44                                                        struct cli_credentials *machine_account, 
  45                                                        struct smb_krb5_context *smb_krb5_context,
  46                                                        krb5_principal *salt_princ)
  47 {
  48         krb5_error_code ret;
  49         char *machine_username;
  50         char *salt_body;
  51         char *lower_realm;
  52         const char *salt_principal;
  53         struct principal_container *mem_ctx = talloc(parent_ctx, struct principal_container);
  54         if (!mem_ctx) {
  55                 return ENOMEM;
  56         }
  57 
  58         salt_principal = cli_credentials_get_salt_principal(machine_account);
  59         if (salt_principal) {
  60                 ret = krb5_parse_name(smb_krb5_context->krb5_context, salt_principal, salt_princ); 
  61         } else {
  62                 machine_username = talloc_strdup(mem_ctx, cli_credentials_get_username(machine_account));
  63                 
  64                 if (!machine_username) {
  65                         talloc_free(mem_ctx);
  66                         return ENOMEM;
  67                 }
  68                 
  69                 if (machine_username[strlen(machine_username)-1] == '$') {
  70                         machine_username[strlen(machine_username)-1] = '\0';
  71                 }
  72                 lower_realm = strlower_talloc(mem_ctx, cli_credentials_get_realm(machine_account));
  73                 if (!lower_realm) {
  74                         talloc_free(mem_ctx);
  75                         return ENOMEM;
  76                 }
  77                 
  78                 salt_body = talloc_asprintf(mem_ctx, "%s.%s", machine_username, 
  79                                             lower_realm);
  80                 if (!salt_body) {
  81                         talloc_free(mem_ctx);
  82                 return ENOMEM;
  83                 }
  84                 
  85                 ret = krb5_make_principal(smb_krb5_context->krb5_context, salt_princ, 
  86                                           cli_credentials_get_realm(machine_account), 
  87                                           "host", salt_body, NULL);
  88         } 
  89 
  90         if (ret == 0) {
  91                 /* This song-and-dance effectivly puts the principal
  92                  * into talloc, so we can't loose it. */
  93                 mem_ctx->smb_krb5_context = talloc_reference(mem_ctx, smb_krb5_context);
  94                 mem_ctx->principal = *salt_princ;
  95                 talloc_set_destructor(mem_ctx, free_principal);
  96         }
  97         return ret;
  98 }
  99 
 100 /* Obtain the principal set on this context.  Requires a
 101  * smb_krb5_context because we are doing krb5 principal parsing with
 102  * the library routines.  The returned princ is placed in the talloc
 103  * system by means of a destructor (do *not* free). */
 104 
 105  krb5_error_code principal_from_credentials(TALLOC_CTX *parent_ctx, 
     /* [<][>][^][v][top][bottom][index][help] */
 106                                             struct cli_credentials *credentials, 
 107                                             struct smb_krb5_context *smb_krb5_context,
 108                                             krb5_principal *princ)
 109 {
 110         krb5_error_code ret;
 111         const char *princ_string;
 112         struct principal_container *mem_ctx = talloc(parent_ctx, struct principal_container);
 113         if (!mem_ctx) {
 114                 return ENOMEM;
 115         }
 116         
 117         princ_string = cli_credentials_get_principal(credentials, mem_ctx);
 118 
 119         /* A NULL here has meaning, as the gssapi server case will
 120          * then use the principal from the client */
 121         if (!princ_string) {
 122                 talloc_free(mem_ctx);
 123                 princ = NULL;
 124                 return 0;
 125         }
 126 
 127         ret = krb5_parse_name(smb_krb5_context->krb5_context,
 128                               princ_string, princ);
 129 
 130         if (ret == 0) {
 131                 /* This song-and-dance effectivly puts the principal
 132                  * into talloc, so we can't loose it. */
 133                 mem_ctx->smb_krb5_context = talloc_reference(mem_ctx, smb_krb5_context);
 134                 mem_ctx->principal = *princ;
 135                 talloc_set_destructor(mem_ctx, free_principal);
 136         }
 137         return ret;
 138 }
 139 
 140 /**
 141  * Return a freshly allocated ccache (destroyed by destructor on child
 142  * of parent_ctx), for a given set of client credentials 
 143  */
 144 
 145  krb5_error_code kinit_to_ccache(TALLOC_CTX *parent_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 146                                  struct cli_credentials *credentials,
 147                                  struct smb_krb5_context *smb_krb5_context,
 148                                  krb5_ccache ccache) 
 149 {
 150         krb5_error_code ret;
 151         const char *password;
 152         time_t kdc_time = 0;
 153         krb5_principal princ;
 154         int tries;
 155         TALLOC_CTX *mem_ctx = talloc_new(parent_ctx);
 156 
 157         if (!mem_ctx) {
 158                 return ENOMEM;
 159         }
 160 
 161         ret = principal_from_credentials(mem_ctx, credentials, smb_krb5_context, &princ);
 162         if (ret) {
 163                 talloc_free(mem_ctx);
 164                 return ret;
 165         }
 166 
 167         password = cli_credentials_get_password(credentials);
 168 
 169         tries = 2;
 170         while (tries--) {
 171                 if (password) {
 172                         ret = kerberos_kinit_password_cc(smb_krb5_context->krb5_context, ccache, 
 173                                                          princ, 
 174                                                          password, NULL, &kdc_time);
 175                 } else {
 176                         /* No password available, try to use a keyblock instead */
 177                         
 178                         krb5_keyblock keyblock;
 179                         const struct samr_Password *mach_pwd;
 180                         mach_pwd = cli_credentials_get_nt_hash(credentials, mem_ctx);
 181                         if (!mach_pwd) {
 182                                 talloc_free(mem_ctx);
 183                                 DEBUG(1, ("kinit_to_ccache: No password available for kinit\n"));
 184                                 return EINVAL;
 185                         }
 186                         ret = krb5_keyblock_init(smb_krb5_context->krb5_context,
 187                                                  ETYPE_ARCFOUR_HMAC_MD5,
 188                                                  mach_pwd->hash, sizeof(mach_pwd->hash), 
 189                                                  &keyblock);
 190                         
 191                         if (ret == 0) {
 192                                 ret = kerberos_kinit_keyblock_cc(smb_krb5_context->krb5_context, ccache, 
 193                                                                  princ,
 194                                                                  &keyblock, NULL, &kdc_time);
 195                                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &keyblock);
 196                         }
 197                 }
 198 
 199                 if (ret == KRB5KRB_AP_ERR_SKEW || ret == KRB5_KDCREP_SKEW) {
 200                         /* Perhaps we have been given an invalid skew, so try again without it */
 201                         time_t t = time(NULL);
 202                         krb5_set_real_time(smb_krb5_context->krb5_context, t, 0);
 203                 } else {
 204                         /* not a skew problem */
 205                         break;
 206                 }
 207         }
 208 
 209         if (ret == KRB5KRB_AP_ERR_SKEW || ret == KRB5_KDCREP_SKEW) {
 210                 DEBUG(1,("kinit for %s failed (%s)\n", 
 211                          cli_credentials_get_principal(credentials, mem_ctx), 
 212                          smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
 213                                                     ret, mem_ctx)));
 214                 talloc_free(mem_ctx);
 215                 return ret;
 216         }
 217 
 218         /* cope with ticket being in the future due to clock skew */
 219         if ((unsigned)kdc_time > time(NULL)) {
 220                 time_t t = time(NULL);
 221                 int time_offset =(unsigned)kdc_time-t;
 222                 DEBUG(4,("Advancing clock by %d seconds to cope with clock skew\n", time_offset));
 223                 krb5_set_real_time(smb_krb5_context->krb5_context, t + time_offset + 1, 0);
 224         }
 225         
 226         if (ret == KRB5KDC_ERR_PREAUTH_FAILED && cli_credentials_wrong_password(credentials)) {
 227                 ret = kinit_to_ccache(parent_ctx,
 228                                       credentials,
 229                                       smb_krb5_context,
 230                                       ccache); 
 231         }
 232         if (ret) {
 233                 DEBUG(1,("kinit for %s failed (%s)\n", 
 234                          cli_credentials_get_principal(credentials, mem_ctx), 
 235                          smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
 236                                                     ret, mem_ctx)));
 237                 talloc_free(mem_ctx);
 238                 return ret;
 239         } 
 240         talloc_free(mem_ctx);
 241         return 0;
 242 }
 243 
 244 static krb5_error_code free_keytab(struct keytab_container *ktc)
     /* [<][>][^][v][top][bottom][index][help] */
 245 {
 246         return krb5_kt_close(ktc->smb_krb5_context->krb5_context, ktc->keytab);
 247 }
 248 
 249 krb5_error_code smb_krb5_open_keytab(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 250                          struct smb_krb5_context *smb_krb5_context, 
 251                          const char *keytab_name, struct keytab_container **ktc) 
 252 {
 253         krb5_keytab keytab;
 254         krb5_error_code ret;
 255         ret = krb5_kt_resolve(smb_krb5_context->krb5_context, keytab_name, &keytab);
 256         if (ret) {
 257                 DEBUG(1,("failed to open krb5 keytab: %s\n", 
 258                          smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
 259                                                     ret, mem_ctx)));
 260                 return ret;
 261         }
 262 
 263         *ktc = talloc(mem_ctx, struct keytab_container);
 264         if (!*ktc) {
 265                 return ENOMEM;
 266         }
 267 
 268         (*ktc)->smb_krb5_context = talloc_reference(*ktc, smb_krb5_context);
 269         (*ktc)->keytab = keytab;
 270         talloc_set_destructor(*ktc, free_keytab);
 271 
 272         return 0;
 273 }
 274 
 275 static krb5_error_code keytab_add_keys(TALLOC_CTX *parent_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 276                                        const char *princ_string,
 277                                        krb5_principal princ,
 278                                        krb5_principal salt_princ,
 279                                        int kvno,
 280                                        const char *password_s,
 281                                        struct smb_krb5_context *smb_krb5_context,
 282                                        const char **enctype_strings,
 283                                        krb5_keytab keytab)
 284 {
 285         int i;
 286         krb5_error_code ret;
 287         krb5_data password;
 288         TALLOC_CTX *mem_ctx = talloc_new(parent_ctx);
 289         if (!mem_ctx) {
 290                 return ENOMEM;
 291         }
 292 
 293         password.data = discard_const_p(char *, password_s);
 294         password.length = strlen(password_s);
 295 
 296         for (i=0; enctype_strings[i]; i++) {
 297                 krb5_keytab_entry entry;
 298                 krb5_enctype enctype;
 299                 ret = krb5_string_to_enctype(smb_krb5_context->krb5_context, enctype_strings[i], &enctype);
 300                 if (ret != 0) {
 301                         DEBUG(1, ("Failed to interpret %s as a krb5 encryption type: %s\n",                               
 302                                   enctype_strings[i],
 303                                   smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
 304                                                              ret, mem_ctx)));
 305                         talloc_free(mem_ctx);
 306                         return ret;
 307                 }
 308                 ret = create_kerberos_key_from_string(smb_krb5_context->krb5_context, 
 309                                                       salt_princ, &password, &entry.keyblock, enctype);
 310                 if (ret != 0) {
 311                         talloc_free(mem_ctx);
 312                         return ret;
 313                 }
 314 
 315                 entry.principal = princ;
 316                 entry.vno       = kvno;
 317                 ret = krb5_kt_add_entry(smb_krb5_context->krb5_context, keytab, &entry);
 318                 if (ret != 0) {
 319                         DEBUG(1, ("Failed to add %s entry for %s(kvno %d) to keytab: %s\n",
 320                                   enctype_strings[i],
 321                                   princ_string,
 322                                   kvno,
 323                                   smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
 324                                                              ret, mem_ctx)));
 325                         talloc_free(mem_ctx);
 326                         krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &entry.keyblock);
 327                         return ret;
 328                 }
 329 
 330                 DEBUG(5, ("Added %s(kvno %d) to keytab (%s)\n", 
 331                           princ_string, kvno,
 332                           enctype_strings[i]));
 333                 
 334                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &entry.keyblock);
 335         }
 336         talloc_free(mem_ctx);
 337         return 0;
 338 }
 339 
 340 static krb5_error_code create_keytab(TALLOC_CTX *parent_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 341                          struct cli_credentials *machine_account,
 342                          struct smb_krb5_context *smb_krb5_context,
 343                          const char **enctype_strings,
 344                          krb5_keytab keytab,
 345                          bool add_old) 
 346 {
 347         krb5_error_code ret;
 348         const char *password_s;
 349         const char *old_secret;
 350         int kvno;
 351         krb5_principal salt_princ;
 352         krb5_principal princ;
 353         const char *princ_string;
 354 
 355         TALLOC_CTX *mem_ctx = talloc_new(parent_ctx);
 356         if (!mem_ctx) {
 357                 return ENOMEM;
 358         }
 359 
 360         princ_string = cli_credentials_get_principal(machine_account, mem_ctx);
 361         /* Get the principal we will store the new keytab entries under */
 362         ret = principal_from_credentials(mem_ctx, machine_account, smb_krb5_context, &princ);
 363         if (ret) {
 364                 DEBUG(1,("create_keytab: makeing krb5 principal failed (%s)\n",
 365                          smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
 366                                                     ret, mem_ctx)));
 367                 talloc_free(mem_ctx);
 368                 return ret;
 369         }
 370 
 371         /* The salt used to generate these entries may be different however, fetch that */
 372         ret = salt_principal_from_credentials(mem_ctx, machine_account, 
 373                                               smb_krb5_context, 
 374                                               &salt_princ);
 375         if (ret) {
 376                 DEBUG(1,("create_keytab: makeing salt principal failed (%s)\n",
 377                          smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
 378                                                     ret, mem_ctx)));
 379                 talloc_free(mem_ctx);
 380                 return ret;
 381         }
 382 
 383         /* Finally, do the dance to get the password to put in the entry */
 384         password_s = cli_credentials_get_password(machine_account);
 385         if (!password_s) {
 386                 krb5_keytab_entry entry;
 387                 const struct samr_Password *mach_pwd;
 388 
 389                 if (!str_list_check(enctype_strings, "arcfour-hmac-md5")) {
 390                         DEBUG(1, ("Asked to create keytab, but with only an NT hash supplied, "
 391                                   "but not listing arcfour-hmac-md5 as an enc type to include in the keytab!\n"));
 392                         talloc_free(mem_ctx);
 393                         return EINVAL;
 394                 }
 395 
 396                 /* If we don't have the plaintext password, try for
 397                  * the MD4 password hash */
 398                 mach_pwd = cli_credentials_get_nt_hash(machine_account, mem_ctx);
 399                 if (!mach_pwd) {
 400                         /* OK, nothing to do here */
 401                         talloc_free(mem_ctx);
 402                         return 0;
 403                 }
 404                 ret = krb5_keyblock_init(smb_krb5_context->krb5_context,
 405                                          ETYPE_ARCFOUR_HMAC_MD5,
 406                                          mach_pwd->hash, sizeof(mach_pwd->hash), 
 407                                          &entry.keyblock);
 408                 if (ret) {
 409                         DEBUG(1, ("create_keytab: krb5_keyblock_init failed: %s\n",
 410                                   smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
 411                                                              ret, mem_ctx)));
 412                         talloc_free(mem_ctx);
 413                         return ret;
 414                 }
 415 
 416                 entry.principal = princ;
 417                 entry.vno       = cli_credentials_get_kvno(machine_account);
 418                 ret = krb5_kt_add_entry(smb_krb5_context->krb5_context, keytab, &entry);
 419                 if (ret) {
 420                         DEBUG(1, ("Failed to add ARCFOUR_HMAC (only) entry for %s to keytab: %s",
 421                                   cli_credentials_get_principal(machine_account, mem_ctx), 
 422                                   smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
 423                                                              ret, mem_ctx)));
 424                         talloc_free(mem_ctx);
 425                         krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &entry.keyblock);
 426                         return ret;
 427                 }
 428                 
 429                 DEBUG(5, ("Added %s(kvno %d) to keytab (arcfour-hmac-md5)\n", 
 430                           cli_credentials_get_principal(machine_account, mem_ctx),
 431                           cli_credentials_get_kvno(machine_account)));
 432 
 433                 krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &entry.keyblock);
 434 
 435                 /* Can't go any further, we only have this one key */
 436                 talloc_free(mem_ctx);
 437                 return 0;
 438         }
 439         
 440         kvno = cli_credentials_get_kvno(machine_account);
 441         /* good, we actually have the real plaintext */
 442         ret = keytab_add_keys(mem_ctx, princ_string, princ, salt_princ, 
 443                               kvno, password_s, smb_krb5_context, 
 444                               enctype_strings, keytab);
 445         if (!ret) {
 446                 talloc_free(mem_ctx);
 447                 return ret;
 448         }
 449 
 450         if (!add_old || kvno == 0) {
 451                 talloc_free(mem_ctx);
 452                 return 0;
 453         }
 454 
 455         old_secret = cli_credentials_get_old_password(machine_account);
 456         if (!old_secret) {
 457                 talloc_free(mem_ctx);
 458                 return 0;
 459         }
 460         
 461         ret = keytab_add_keys(mem_ctx, princ_string, princ, salt_princ, 
 462                               kvno - 1, old_secret, smb_krb5_context, 
 463                               enctype_strings, keytab);
 464         if (!ret) {
 465                 talloc_free(mem_ctx);
 466                 return ret;
 467         }
 468 
 469         talloc_free(mem_ctx);
 470         return 0;
 471 }
 472 
 473 
 474 /*
 475  * Walk the keytab, looking for entries of this principal name, with KVNO other than current kvno -1.
 476  *
 477  * These entries are now stale, we only keep the current, and previous entries around.
 478  *
 479  * Inspired by the code in Samba3 for 'use kerberos keytab'.
 480  *
 481  */
 482 
 483 static krb5_error_code remove_old_entries(TALLOC_CTX *parent_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 484                                           struct cli_credentials *machine_account,
 485                                           struct smb_krb5_context *smb_krb5_context,
 486                                           krb5_keytab keytab, bool *found_previous)
 487 {
 488         krb5_error_code ret, ret2;
 489         krb5_kt_cursor cursor;
 490         krb5_principal princ;
 491         int kvno;
 492         TALLOC_CTX *mem_ctx = talloc_new(parent_ctx);
 493         const char *princ_string;
 494         if (!mem_ctx) {
 495                 return ENOMEM;
 496         }
 497 
 498         *found_previous = false;
 499         princ_string = cli_credentials_get_principal(machine_account, mem_ctx);
 500 
 501         /* Get the principal we will store the new keytab entries under */
 502         ret = principal_from_credentials(mem_ctx, machine_account, smb_krb5_context, &princ);
 503         if (ret) {
 504                 DEBUG(1,("update_keytab: makeing krb5 principal failed (%s)\n",
 505                          smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
 506                                                     ret, mem_ctx)));
 507                 talloc_free(mem_ctx);
 508                 return ret;
 509         }
 510 
 511         kvno = cli_credentials_get_kvno(machine_account);
 512 
 513         /* for each entry in the keytab */
 514         ret = krb5_kt_start_seq_get(smb_krb5_context->krb5_context, keytab, &cursor);
 515         switch (ret) {
 516         case 0:
 517                 break;
 518         case HEIM_ERR_OPNOTSUPP:
 519         case ENOENT:
 520         case KRB5_KT_END:
 521                 /* no point enumerating if there isn't anything here */
 522                 talloc_free(mem_ctx);
 523                 return 0;
 524         default:
 525                 DEBUG(1,("failed to open keytab for read of old entries: %s\n",
 526                          smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
 527                                                     ret, mem_ctx)));
 528                 talloc_free(mem_ctx);
 529                 return ret;
 530         }
 531 
 532         while (!ret) {
 533                 krb5_keytab_entry entry;
 534                 ret = krb5_kt_next_entry(smb_krb5_context->krb5_context, keytab, &entry, &cursor);
 535                 if (ret) {
 536                         break;
 537                 }
 538                 /* if it matches our principal */
 539                 if (!krb5_kt_compare(smb_krb5_context->krb5_context, &entry, princ, 0, 0)) {
 540                         /* Free the entry, it wasn't the one we were looking for anyway */
 541                         krb5_kt_free_entry(smb_krb5_context->krb5_context, &entry);
 542                         continue;
 543                 }
 544 
 545                 /* delete it, if it is not kvno -1 */
 546                 if (entry.vno != (kvno - 1 )) {
 547                         /* Release the enumeration.  We are going to
 548                          * have to start this from the top again,
 549                          * because deletes during enumeration may not
 550                          * always be consistant.
 551                          *
 552                          * Also, the enumeration locks a FILE: keytab
 553                          */
 554                 
 555                         krb5_kt_end_seq_get(smb_krb5_context->krb5_context, keytab, &cursor);
 556 
 557                         ret = krb5_kt_remove_entry(smb_krb5_context->krb5_context, keytab, &entry);
 558                         krb5_kt_free_entry(smb_krb5_context->krb5_context, &entry);
 559 
 560                         /* Deleted: Restart from the top */
 561                         ret2 = krb5_kt_start_seq_get(smb_krb5_context->krb5_context, keytab, &cursor);
 562                         if (ret2) {
 563                                 krb5_kt_free_entry(smb_krb5_context->krb5_context, &entry);
 564                                 DEBUG(1,("failed to restart enumeration of keytab: %s\n",
 565                                          smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
 566                                                                     ret, mem_ctx)));
 567                                 
 568                                 talloc_free(mem_ctx);
 569                                 return ret2;
 570                         }
 571 
 572                         if (ret) {
 573                                 break;
 574                         }
 575                         
 576                 } else {
 577                         *found_previous = true;
 578                 }
 579                 
 580                 /* Free the entry, we don't need it any more */
 581                 krb5_kt_free_entry(smb_krb5_context->krb5_context, &entry);
 582                 
 583                 
 584         }
 585         krb5_kt_end_seq_get(smb_krb5_context->krb5_context, keytab, &cursor);
 586 
 587         switch (ret) {
 588         case 0:
 589                 break;
 590         case ENOENT:
 591         case KRB5_KT_END:
 592                 ret = 0;
 593                 break;
 594         default:
 595                 DEBUG(1,("failed in deleting old entries for principal: %s: %s\n",
 596                          princ_string, 
 597                          smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
 598                                                     ret, mem_ctx)));
 599         }
 600         talloc_free(mem_ctx);
 601         return ret;
 602 }
 603 
 604 krb5_error_code smb_krb5_update_keytab(TALLOC_CTX *parent_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 605                            struct cli_credentials *machine_account,
 606                            struct smb_krb5_context *smb_krb5_context,
 607                            const char **enctype_strings,
 608                            struct keytab_container *keytab_container) 
 609 {
 610         krb5_error_code ret;
 611         bool found_previous;
 612         TALLOC_CTX *mem_ctx = talloc_new(parent_ctx);
 613         if (!mem_ctx) {
 614                 return ENOMEM;
 615         }
 616 
 617         ret = remove_old_entries(mem_ctx, machine_account, 
 618                                  smb_krb5_context, keytab_container->keytab, &found_previous);
 619         if (ret != 0) {
 620                 talloc_free(mem_ctx);
 621                 return ret;
 622         }
 623         
 624         /* Create a new keytab.  If during the cleanout we found
 625          * entires for kvno -1, then don't try and duplicate them.
 626          * Otherwise, add kvno, and kvno -1 */
 627         
 628         ret = create_keytab(mem_ctx, machine_account, smb_krb5_context, 
 629                             enctype_strings, 
 630                             keytab_container->keytab, 
 631                             found_previous ? false : true);
 632         talloc_free(mem_ctx);
 633         return ret;
 634 }
 635 
 636 krb5_error_code smb_krb5_create_memory_keytab(TALLOC_CTX *parent_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 637                                            struct cli_credentials *machine_account,
 638                                            struct smb_krb5_context *smb_krb5_context,
 639                                            const char **enctype_strings,
 640                                            struct keytab_container **keytab_container) 
 641 {
 642         krb5_error_code ret;
 643         TALLOC_CTX *mem_ctx = talloc_new(parent_ctx);
 644         const char *rand_string;
 645         const char *keytab_name;
 646         if (!mem_ctx) {
 647                 return ENOMEM;
 648         }
 649         
 650         *keytab_container = talloc(mem_ctx, struct keytab_container);
 651 
 652         rand_string = generate_random_str(mem_ctx, 16);
 653         if (!rand_string) {
 654                 talloc_free(mem_ctx);
 655                 return ENOMEM;
 656         }
 657 
 658         keytab_name = talloc_asprintf(mem_ctx, "MEMORY:%s", 
 659                                       rand_string);
 660         if (!keytab_name) {
 661                 talloc_free(mem_ctx);
 662                 return ENOMEM;
 663         }
 664 
 665         ret = smb_krb5_open_keytab(mem_ctx, smb_krb5_context, keytab_name, keytab_container);
 666         if (ret) {
 667                 return ret;
 668         }
 669 
 670         ret = smb_krb5_update_keytab(mem_ctx, machine_account, smb_krb5_context, enctype_strings, *keytab_container);
 671         if (ret == 0) {
 672                 talloc_steal(parent_ctx, *keytab_container);
 673         } else {
 674                 *keytab_container = NULL;
 675         }
 676         talloc_free(mem_ctx);
 677         return ret;
 678 }
 679 

/* [<][>][^][v][top][bottom][index][help] */