root/source3/libads/kerberos_keytab.c

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

DEFINITIONS

This source file includes following definitions.
  1. smb_krb5_kt_add_entry_ext
  2. smb_krb5_kt_add_entry
  3. ads_keytab_add_entry
  4. ads_keytab_flush
  5. ads_keytab_create_default
  6. ads_keytab_list

   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 
  30 #ifdef HAVE_KRB5
  31 
  32 /**********************************************************************
  33 **********************************************************************/
  34 
  35 int smb_krb5_kt_add_entry_ext(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
  36                               krb5_keytab keytab,
  37                               krb5_kvno kvno,
  38                               const char *princ_s,
  39                               krb5_enctype *enctypes,
  40                               krb5_data password,
  41                               bool no_salt,
  42                               bool keep_old_entries)
  43 {
  44         krb5_error_code ret = 0;
  45         krb5_kt_cursor cursor;
  46         krb5_keytab_entry kt_entry;
  47         krb5_principal princ = NULL;
  48         int i;
  49         char *ktprinc = NULL;
  50 
  51         ZERO_STRUCT(kt_entry);
  52         ZERO_STRUCT(cursor);
  53         
  54         ret = smb_krb5_parse_name(context, princ_s, &princ);
  55         if (ret) {
  56                 DEBUG(1,("smb_krb5_kt_add_entry_ext: smb_krb5_parse_name(%s) failed (%s)\n", princ_s, error_message(ret)));
  57                 goto out;
  58         }
  59 
  60         /* Seek and delete old keytab entries */
  61         ret = krb5_kt_start_seq_get(context, keytab, &cursor);
  62         if (ret != KRB5_KT_END && ret != ENOENT ) {
  63                 DEBUG(3,("smb_krb5_kt_add_entry_ext: Will try to delete old keytab entries\n"));
  64                 while(!krb5_kt_next_entry(context, keytab, &kt_entry, &cursor)) {
  65                         bool compare_name_ok = False;
  66 
  67                         ret = smb_krb5_unparse_name(talloc_tos(), context, kt_entry.principal, &ktprinc);
  68                         if (ret) {
  69                                 DEBUG(1,("smb_krb5_kt_add_entry_ext: smb_krb5_unparse_name failed (%s)\n",
  70                                         error_message(ret)));
  71                                 goto out;
  72                         }
  73 
  74                         /*---------------------------------------------------------------------------
  75                          * Save the entries with kvno - 1.   This is what microsoft does
  76                          * to allow people with existing sessions that have kvno - 1 to still
  77                          * work.   Otherwise, when the password for the machine changes, all
  78                          * kerberizied sessions will 'break' until either the client reboots or
  79                          * the client's session key expires and they get a new session ticket
  80                          * with the new kvno.
  81                          */
  82 
  83 #ifdef HAVE_KRB5_KT_COMPARE
  84                         compare_name_ok = (krb5_kt_compare(context, &kt_entry, princ, 0, 0) == True);
  85 #else
  86                         compare_name_ok = (strcmp(ktprinc, princ_s) == 0);
  87 #endif
  88 
  89                         if (!compare_name_ok) {
  90                                 DEBUG(10,("smb_krb5_kt_add_entry_ext: ignoring keytab entry principal %s, kvno = %d\n",
  91                                         ktprinc, kt_entry.vno));
  92                         }
  93 
  94                         TALLOC_FREE(ktprinc);
  95 
  96                         if (compare_name_ok) {
  97                                 if (kt_entry.vno == kvno - 1) {
  98                                         DEBUG(5,("smb_krb5_kt_add_entry_ext: Saving previous (kvno %d) entry for principal: %s.\n",
  99                                                 kvno - 1, princ_s));
 100                                 } else if (!keep_old_entries) {
 101                                         DEBUG(5,("smb_krb5_kt_add_entry_ext: Found old entry for principal: %s (kvno %d) - trying to remove it.\n",
 102                                                 princ_s, kt_entry.vno));
 103                                         ret = krb5_kt_end_seq_get(context, keytab, &cursor);
 104                                         ZERO_STRUCT(cursor);
 105                                         if (ret) {
 106                                                 DEBUG(1,("smb_krb5_kt_add_entry_ext: krb5_kt_end_seq_get() failed (%s)\n",
 107                                                         error_message(ret)));
 108                                                 goto out;
 109                                         }
 110                                         ret = krb5_kt_remove_entry(context, keytab, &kt_entry);
 111                                         if (ret) {
 112                                                 DEBUG(1,("smb_krb5_kt_add_entry_ext: krb5_kt_remove_entry failed (%s)\n",
 113                                                         error_message(ret)));
 114                                                 goto out;
 115                                         }
 116 
 117                                         DEBUG(5,("smb_krb5_kt_add_entry_ext: removed old entry for principal: %s (kvno %d).\n",
 118                                                 princ_s, kt_entry.vno));
 119 
 120                                         ret = krb5_kt_start_seq_get(context, keytab, &cursor);
 121                                         if (ret) {
 122                                                 DEBUG(1,("smb_krb5_kt_add_entry_ext: krb5_kt_start_seq failed (%s)\n",
 123                                                         error_message(ret)));
 124                                                 goto out;
 125                                         }
 126                                         ret = smb_krb5_kt_free_entry(context, &kt_entry);
 127                                         ZERO_STRUCT(kt_entry);
 128                                         if (ret) {
 129                                                 DEBUG(1,("smb_krb5_kt_add_entry_ext: krb5_kt_remove_entry failed (%s)\n",
 130                                                         error_message(ret)));
 131                                                 goto out;
 132                                         }
 133                                         continue;
 134                                 }
 135                         }
 136 
 137                         /* Not a match, just free this entry and continue. */
 138                         ret = smb_krb5_kt_free_entry(context, &kt_entry);
 139                         ZERO_STRUCT(kt_entry);
 140                         if (ret) {
 141                                 DEBUG(1,("smb_krb5_kt_add_entry_ext: smb_krb5_kt_free_entry failed (%s)\n", error_message(ret)));
 142                                 goto out;
 143                         }
 144                 }
 145 
 146                 ret = krb5_kt_end_seq_get(context, keytab, &cursor);
 147                 ZERO_STRUCT(cursor);
 148                 if (ret) {
 149                         DEBUG(1,("smb_krb5_kt_add_entry_ext: krb5_kt_end_seq_get failed (%s)\n",error_message(ret)));
 150                         goto out;
 151                 }
 152         }
 153 
 154         /* Ensure we don't double free. */
 155         ZERO_STRUCT(kt_entry);
 156         ZERO_STRUCT(cursor);
 157 
 158         /* If we get here, we have deleted all the old entries with kvno's not equal to the current kvno-1. */
 159 
 160         /* Now add keytab entries for all encryption types */
 161         for (i = 0; enctypes[i]; i++) {
 162                 krb5_keyblock *keyp;
 163 
 164                 keyp = KRB5_KT_KEY(&kt_entry);
 165 
 166                 if (create_kerberos_key_from_string(context, princ, &password, keyp, enctypes[i], no_salt)) {
 167                         continue;
 168                 }
 169 
 170                 kt_entry.principal = princ;
 171                 kt_entry.vno       = kvno;
 172 
 173                 DEBUG(3,("smb_krb5_kt_add_entry_ext: adding keytab entry for (%s) with encryption type (%d) and version (%d)\n",
 174                         princ_s, enctypes[i], kt_entry.vno));
 175                 ret = krb5_kt_add_entry(context, keytab, &kt_entry);
 176                 krb5_free_keyblock_contents(context, keyp);
 177                 ZERO_STRUCT(kt_entry);
 178                 if (ret) {
 179                         DEBUG(1,("smb_krb5_kt_add_entry_ext: adding entry to keytab failed (%s)\n", error_message(ret)));
 180                         goto out;
 181                 }
 182         }
 183 
 184 
 185 out:
 186         {
 187                 krb5_keytab_entry zero_kt_entry;
 188                 ZERO_STRUCT(zero_kt_entry);
 189                 if (memcmp(&zero_kt_entry, &kt_entry, sizeof(krb5_keytab_entry))) {
 190                         smb_krb5_kt_free_entry(context, &kt_entry);
 191                 }
 192         }
 193         if (princ) {
 194                 krb5_free_principal(context, princ);
 195         }
 196         
 197         {
 198                 krb5_kt_cursor zero_csr;
 199                 ZERO_STRUCT(zero_csr);
 200                 if ((memcmp(&cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && keytab) {
 201                         krb5_kt_end_seq_get(context, keytab, &cursor);  
 202                 }
 203         }
 204         
 205         return (int)ret;
 206 }
 207 
 208 static int smb_krb5_kt_add_entry(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 209                                  krb5_keytab keytab,
 210                                  krb5_kvno kvno,
 211                                  const char *princ_s,
 212                                  krb5_enctype *enctypes,
 213                                  krb5_data password)
 214 {
 215         return smb_krb5_kt_add_entry_ext(context,
 216                                          keytab,
 217                                          kvno,
 218                                          princ_s,
 219                                          enctypes,
 220                                          password,
 221                                          false,
 222                                          false);
 223 }
 224 
 225 /**********************************************************************
 226  Adds a single service principal, i.e. 'host' to the system keytab
 227 ***********************************************************************/
 228 
 229 int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc)
     /* [<][>][^][v][top][bottom][index][help] */
 230 {
 231         krb5_error_code ret = 0;
 232         krb5_context context = NULL;
 233         krb5_keytab keytab = NULL;
 234         krb5_data password;
 235         krb5_kvno kvno;
 236         krb5_enctype enctypes[4] = { ENCTYPE_DES_CBC_CRC, ENCTYPE_DES_CBC_MD5, 0, 0 };
 237         char *princ_s = NULL, *short_princ_s = NULL;
 238         char *password_s = NULL;
 239         char *my_fqdn;
 240         TALLOC_CTX *ctx = NULL;
 241         char *machine_name;
 242 
 243 #if defined(ENCTYPE_ARCFOUR_HMAC)
 244         enctypes[2] = ENCTYPE_ARCFOUR_HMAC;
 245 #endif
 246 
 247         initialize_krb5_error_table();
 248         ret = krb5_init_context(&context);
 249         if (ret) {
 250                 DEBUG(1,("ads_keytab_add_entry: could not krb5_init_context: %s\n",error_message(ret)));
 251                 return -1;
 252         }
 253 
 254         ret = smb_krb5_open_keytab(context, NULL, True, &keytab);
 255         if (ret) {
 256                 DEBUG(1,("ads_keytab_add_entry: smb_krb5_open_keytab failed (%s)\n", error_message(ret)));
 257                 goto out;
 258         }
 259 
 260         /* retrieve the password */
 261         if (!secrets_init()) {
 262                 DEBUG(1,("ads_keytab_add_entry: secrets_init failed\n"));
 263                 ret = -1;
 264                 goto out;
 265         }
 266         password_s = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
 267         if (!password_s) {
 268                 DEBUG(1,("ads_keytab_add_entry: failed to fetch machine password\n"));
 269                 ret = -1;
 270                 goto out;
 271         }
 272         ZERO_STRUCT(password);
 273         password.data = password_s;
 274         password.length = strlen(password_s);
 275 
 276         /* we need the dNSHostName value here */
 277         
 278         if ( (ctx = talloc_init("ads_keytab_add_entry")) == NULL ) {
 279                 DEBUG(0,("ads_keytab_add_entry: talloc() failed!\n"));
 280                 ret = -1;
 281                 goto out;
 282         }
 283         
 284         if ( (my_fqdn = ads_get_dnshostname( ads, ctx, global_myname())) == NULL ) {
 285                 DEBUG(0,("ads_keytab_add_entry: unable to determine machine account's dns name in AD!\n"));
 286                 ret = -1;
 287                 goto out;       
 288         }
 289         
 290         if ( (machine_name = ads_get_samaccountname( ads, ctx, global_myname())) == NULL ) {
 291                 DEBUG(0,("ads_keytab_add_entry: unable to determine machine account's short name in AD!\n"));
 292                 ret = -1;
 293                 goto out;       
 294         }
 295         /*strip the trailing '$' */
 296         machine_name[strlen(machine_name)-1] = '\0';
 297                 
 298         /* Construct our principal */
 299 
 300         if (strchr_m(srvPrinc, '@')) {
 301                 /* It's a fully-named principal. */
 302                 if (asprintf(&princ_s, "%s", srvPrinc) == -1) {
 303                         ret = -1;
 304                         goto out;
 305                 }
 306         } else if (srvPrinc[strlen(srvPrinc)-1] == '$') {
 307                 /* It's the machine account, as used by smbclient clients. */
 308                 if (asprintf(&princ_s, "%s@%s", srvPrinc, lp_realm()) == -1) {
 309                         ret = -1;
 310                         goto out;
 311                 }
 312         } else {
 313                 /* It's a normal service principal.  Add the SPN now so that we
 314                  * can obtain credentials for it and double-check the salt value
 315                  * used to generate the service's keys. */
 316                  
 317                 if (asprintf(&princ_s, "%s/%s@%s", srvPrinc, my_fqdn, lp_realm()) == -1) {
 318                         ret = -1;
 319                         goto out;
 320                 }
 321                 if (asprintf(&short_princ_s, "%s/%s@%s", srvPrinc, machine_name, lp_realm()) == -1) {
 322                         ret = -1;
 323                         goto out;
 324                 }
 325                 
 326                 /* According to http://support.microsoft.com/kb/326985/en-us, 
 327                    certain principal names are automatically mapped to the host/...
 328                    principal in the AD account.  So only create these in the 
 329                    keytab, not in AD.  --jerry */
 330                    
 331                 if ( !strequal( srvPrinc, "cifs" ) && !strequal(srvPrinc, "host" ) ) {
 332                         DEBUG(3,("ads_keytab_add_entry: Attempting to add/update '%s'\n", princ_s));
 333                         
 334                         if (!ADS_ERR_OK(ads_add_service_principal_name(ads, global_myname(), my_fqdn, srvPrinc))) {
 335                                 DEBUG(1,("ads_keytab_add_entry: ads_add_service_principal_name failed.\n"));
 336                                 goto out;
 337                         }
 338                 }
 339         }
 340 
 341         kvno = (krb5_kvno) ads_get_machine_kvno(ads, global_myname());
 342         if (kvno == -1) {       /* -1 indicates failure, everything else is OK */
 343                 DEBUG(1,("ads_keytab_add_entry: ads_get_machine_kvno failed to determine the system's kvno.\n"));
 344                 ret = -1;
 345                 goto out;
 346         }
 347         
 348         /* add the fqdn principal to the keytab */
 349         
 350         ret = smb_krb5_kt_add_entry( context, keytab, kvno, princ_s, enctypes, password );
 351         if ( ret ) {
 352                 DEBUG(1,("ads_keytab_add_entry: Failed to add entry to keytab file\n"));
 353                 goto out;
 354         }
 355         
 356         /* add the short principal name if we have one */
 357         
 358         if ( short_princ_s ) {
 359                 ret = smb_krb5_kt_add_entry( context, keytab, kvno, short_princ_s, enctypes, password );
 360                 if ( ret ) {
 361                         DEBUG(1,("ads_keytab_add_entry: Failed to add short entry to keytab file\n"));
 362                         goto out;
 363                 }
 364         }
 365 
 366 out:
 367         SAFE_FREE( princ_s );
 368         SAFE_FREE( short_princ_s );
 369         TALLOC_FREE( ctx );
 370         
 371         if (keytab) {
 372                 krb5_kt_close(context, keytab);
 373         }
 374         if (context) {
 375                 krb5_free_context(context);
 376         }
 377         return (int)ret;
 378 }
 379 
 380 /**********************************************************************
 381  Flushes all entries from the system keytab.
 382 ***********************************************************************/
 383 
 384 int ads_keytab_flush(ADS_STRUCT *ads)
     /* [<][>][^][v][top][bottom][index][help] */
 385 {
 386         krb5_error_code ret = 0;
 387         krb5_context context = NULL;
 388         krb5_keytab keytab = NULL;
 389         krb5_kt_cursor cursor;
 390         krb5_keytab_entry kt_entry;
 391         krb5_kvno kvno;
 392 
 393         ZERO_STRUCT(kt_entry);
 394         ZERO_STRUCT(cursor);
 395 
 396         initialize_krb5_error_table();
 397         ret = krb5_init_context(&context);
 398         if (ret) {
 399                 DEBUG(1,("ads_keytab_flush: could not krb5_init_context: %s\n",error_message(ret)));
 400                 return ret;
 401         }
 402 
 403         ret = smb_krb5_open_keytab(context, NULL, True, &keytab);
 404         if (ret) {
 405                 DEBUG(1,("ads_keytab_flush: smb_krb5_open_keytab failed (%s)\n", error_message(ret)));
 406                 goto out;
 407         }
 408 
 409         kvno = (krb5_kvno) ads_get_machine_kvno(ads, global_myname());
 410         if (kvno == -1) {       /* -1 indicates a failure */
 411                 DEBUG(1,("ads_keytab_flush: Error determining the system's kvno.\n"));
 412                 goto out;
 413         }
 414 
 415         ret = krb5_kt_start_seq_get(context, keytab, &cursor);
 416         if (ret != KRB5_KT_END && ret != ENOENT) {
 417                 while (!krb5_kt_next_entry(context, keytab, &kt_entry, &cursor)) {
 418                         ret = krb5_kt_end_seq_get(context, keytab, &cursor);
 419                         ZERO_STRUCT(cursor);
 420                         if (ret) {
 421                                 DEBUG(1,("ads_keytab_flush: krb5_kt_end_seq_get() failed (%s)\n",error_message(ret)));
 422                                 goto out;
 423                         }
 424                         ret = krb5_kt_remove_entry(context, keytab, &kt_entry);
 425                         if (ret) {
 426                                 DEBUG(1,("ads_keytab_flush: krb5_kt_remove_entry failed (%s)\n",error_message(ret)));
 427                                 goto out;
 428                         }
 429                         ret = krb5_kt_start_seq_get(context, keytab, &cursor);
 430                         if (ret) {
 431                                 DEBUG(1,("ads_keytab_flush: krb5_kt_start_seq failed (%s)\n",error_message(ret)));
 432                                 goto out;
 433                         }
 434                         ret = smb_krb5_kt_free_entry(context, &kt_entry);
 435                         ZERO_STRUCT(kt_entry);
 436                         if (ret) {
 437                                 DEBUG(1,("ads_keytab_flush: krb5_kt_remove_entry failed (%s)\n",error_message(ret)));
 438                                 goto out;
 439                         }
 440                 }
 441         }
 442 
 443         /* Ensure we don't double free. */
 444         ZERO_STRUCT(kt_entry);
 445         ZERO_STRUCT(cursor);
 446 
 447         if (!ADS_ERR_OK(ads_clear_service_principal_names(ads, global_myname()))) {
 448                 DEBUG(1,("ads_keytab_flush: Error while clearing service principal listings in LDAP.\n"));
 449                 goto out;
 450         }
 451 
 452 out:
 453 
 454         {
 455                 krb5_keytab_entry zero_kt_entry;
 456                 ZERO_STRUCT(zero_kt_entry);
 457                 if (memcmp(&zero_kt_entry, &kt_entry, sizeof(krb5_keytab_entry))) {
 458                         smb_krb5_kt_free_entry(context, &kt_entry);
 459                 }
 460         }
 461         {
 462                 krb5_kt_cursor zero_csr;
 463                 ZERO_STRUCT(zero_csr);
 464                 if ((memcmp(&cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && keytab) {
 465                         krb5_kt_end_seq_get(context, keytab, &cursor);  
 466                 }
 467         }
 468         if (keytab) {
 469                 krb5_kt_close(context, keytab);
 470         }
 471         if (context) {
 472                 krb5_free_context(context);
 473         }
 474         return ret;
 475 }
 476 
 477 /**********************************************************************
 478  Adds all the required service principals to the system keytab.
 479 ***********************************************************************/
 480 
 481 int ads_keytab_create_default(ADS_STRUCT *ads)
     /* [<][>][^][v][top][bottom][index][help] */
 482 {
 483         krb5_error_code ret = 0;
 484         krb5_context context = NULL;
 485         krb5_keytab keytab = NULL;
 486         krb5_kt_cursor cursor;
 487         krb5_keytab_entry kt_entry;
 488         krb5_kvno kvno;
 489         int i, found = 0;
 490         char *sam_account_name, *upn;
 491         char **oldEntries = NULL, *princ_s[26];
 492         TALLOC_CTX *ctx = NULL;
 493         fstring machine_name;
 494 
 495         memset(princ_s, '\0', sizeof(princ_s));
 496 
 497         fstrcpy( machine_name, global_myname() );
 498 
 499         /* these are the main ones we need */
 500         
 501         if ( (ret = ads_keytab_add_entry(ads, "host") ) != 0 ) {
 502                 DEBUG(1,("ads_keytab_create_default: ads_keytab_add_entry failed while adding 'host'.\n"));
 503                 return ret;
 504         }
 505 
 506 
 507 #if 0   /* don't create the CIFS/... keytab entries since no one except smbd 
 508            really needs them and we will fall back to verifying against secrets.tdb */
 509            
 510         if ( (ret = ads_keytab_add_entry(ads, "cifs")) != 0 ) {
 511                 DEBUG(1,("ads_keytab_create_default: ads_keytab_add_entry failed while adding 'cifs'.\n"));
 512                 return ret;
 513         }
 514 #endif
 515 
 516         if ( (ctx = talloc_init("ads_keytab_create_default")) == NULL ) {
 517                 DEBUG(0,("ads_keytab_create_default: talloc() failed!\n"));
 518                 return -1;
 519         }
 520 
 521         /* now add the userPrincipalName and sAMAccountName entries */
 522 
 523         if ( (sam_account_name = ads_get_samaccountname( ads, ctx, machine_name)) == NULL ) {
 524                 DEBUG(0,("ads_keytab_add_entry: unable to determine machine account's name in AD!\n"));
 525                 TALLOC_FREE( ctx );
 526                 return -1;      
 527         }
 528 
 529         /* upper case the sAMAccountName to make it easier for apps to 
 530            know what case to use in the keytab file */
 531 
 532         strupper_m( sam_account_name ); 
 533 
 534         if ( (ret = ads_keytab_add_entry(ads, sam_account_name )) != 0 ) {
 535                 DEBUG(1,("ads_keytab_create_default: ads_keytab_add_entry failed while adding sAMAccountName (%s)\n",
 536                         sam_account_name));
 537                 return ret;
 538         }
 539         
 540         /* remember that not every machine account will have a upn */
 541                 
 542         upn = ads_get_upn( ads, ctx, machine_name);
 543         if ( upn ) {
 544                 if ( (ret = ads_keytab_add_entry(ads, upn)) != 0 ) {
 545                         DEBUG(1,("ads_keytab_create_default: ads_keytab_add_entry failed while adding UPN (%s)\n",
 546                                 upn));
 547                         TALLOC_FREE( ctx );
 548                         return ret;
 549                 }
 550         }
 551 
 552         /* Now loop through the keytab and update any other existing entries... */
 553         
 554         kvno = (krb5_kvno) ads_get_machine_kvno(ads, machine_name);
 555         if (kvno == -1) {
 556                 DEBUG(1,("ads_keytab_create_default: ads_get_machine_kvno failed to determine the system's kvno.\n"));
 557                 TALLOC_FREE(ctx);
 558                 return -1;
 559         }
 560         
 561         DEBUG(3,("ads_keytab_create_default: Searching for keytab entries to "
 562                 "preserve and update.\n"));
 563 
 564         ZERO_STRUCT(kt_entry);
 565         ZERO_STRUCT(cursor);
 566 
 567         initialize_krb5_error_table();
 568         ret = krb5_init_context(&context);
 569         if (ret) {
 570                 DEBUG(1,("ads_keytab_create_default: could not krb5_init_context: %s\n",error_message(ret)));
 571                 TALLOC_FREE(ctx);
 572                 return ret;
 573         }
 574 
 575         ret = smb_krb5_open_keytab(context, NULL, True, &keytab);
 576         if (ret) {
 577                 DEBUG(1,("ads_keytab_create_default: smb_krb5_open_keytab failed (%s)\n", error_message(ret)));
 578                 goto done;
 579         }
 580 
 581         ret = krb5_kt_start_seq_get(context, keytab, &cursor);
 582         if (ret != KRB5_KT_END && ret != ENOENT ) {
 583                 while ((ret = krb5_kt_next_entry(context, keytab, &kt_entry, &cursor)) == 0) {
 584                         smb_krb5_kt_free_entry(context, &kt_entry);
 585                         ZERO_STRUCT(kt_entry);
 586                         found++;
 587                 }
 588         }
 589         krb5_kt_end_seq_get(context, keytab, &cursor);
 590         ZERO_STRUCT(cursor);
 591 
 592         /*
 593          * Hmmm. There is no "rewind" function for the keytab. This means we have a race condition
 594          * where someone else could add entries after we've counted them. Re-open asap to minimise
 595          * the race. JRA.
 596          */
 597         
 598         DEBUG(3, ("ads_keytab_create_default: Found %d entries in the keytab.\n", found));
 599         if (!found) {
 600                 goto done;
 601         }
 602         oldEntries = talloc_array(ctx, char *, found );
 603         if (!oldEntries) {
 604                 DEBUG(1,("ads_keytab_create_default: Failed to allocate space to store the old keytab entries (malloc failed?).\n"));
 605                 ret = -1;
 606                 goto done;
 607         }
 608         memset(oldEntries, '\0', found * sizeof(char *));
 609 
 610         ret = krb5_kt_start_seq_get(context, keytab, &cursor);
 611         if (ret != KRB5_KT_END && ret != ENOENT ) {
 612                 while (krb5_kt_next_entry(context, keytab, &kt_entry, &cursor) == 0) {
 613                         if (kt_entry.vno != kvno) {
 614                                 char *ktprinc = NULL;
 615                                 char *p;
 616 
 617                                 /* This returns a malloc'ed string in ktprinc. */
 618                                 ret = smb_krb5_unparse_name(oldEntries, context, kt_entry.principal, &ktprinc);
 619                                 if (ret) {
 620                                         DEBUG(1,("smb_krb5_unparse_name failed (%s)\n", error_message(ret)));
 621                                         goto done;
 622                                 }
 623                                 /*
 624                                  * From looking at the krb5 source they don't seem to take locale
 625                                  * or mb strings into account. Maybe this is because they assume utf8 ?
 626                                  * In this case we may need to convert from utf8 to mb charset here ? JRA.
 627                                  */
 628                                 p = strchr_m(ktprinc, '@');
 629                                 if (p) {
 630                                         *p = '\0';
 631                                 }
 632 
 633                                 p = strchr_m(ktprinc, '/');
 634                                 if (p) {
 635                                         *p = '\0';
 636                                 }
 637                                 for (i = 0; i < found; i++) {
 638                                         if (!oldEntries[i]) {
 639                                                 oldEntries[i] = ktprinc;
 640                                                 break;
 641                                         }
 642                                         if (!strcmp(oldEntries[i], ktprinc)) {
 643                                                 TALLOC_FREE(ktprinc);
 644                                                 break;
 645                                         }
 646                                 }
 647                                 if (i == found) {
 648                                         TALLOC_FREE(ktprinc);
 649                                 }
 650                         }
 651                         smb_krb5_kt_free_entry(context, &kt_entry);
 652                         ZERO_STRUCT(kt_entry);
 653                 }
 654                 ret = 0;
 655                 for (i = 0; oldEntries[i]; i++) {
 656                         ret |= ads_keytab_add_entry(ads, oldEntries[i]);
 657                         TALLOC_FREE(oldEntries[i]);
 658                 }
 659                 krb5_kt_end_seq_get(context, keytab, &cursor);
 660         }
 661         ZERO_STRUCT(cursor);
 662 
 663 done:
 664 
 665         TALLOC_FREE(oldEntries);
 666         TALLOC_FREE(ctx);
 667 
 668         {
 669                 krb5_keytab_entry zero_kt_entry;
 670                 ZERO_STRUCT(zero_kt_entry);
 671                 if (memcmp(&zero_kt_entry, &kt_entry, sizeof(krb5_keytab_entry))) {
 672                         smb_krb5_kt_free_entry(context, &kt_entry);
 673                 }
 674         }
 675         {
 676                 krb5_kt_cursor zero_csr;
 677                 ZERO_STRUCT(zero_csr);
 678                 if ((memcmp(&cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && keytab) {
 679                         krb5_kt_end_seq_get(context, keytab, &cursor);  
 680                 }
 681         }
 682         if (keytab) {
 683                 krb5_kt_close(context, keytab);
 684         }
 685         if (context) {
 686                 krb5_free_context(context);
 687         }
 688         return ret;
 689 }
 690 
 691 /**********************************************************************
 692  List system keytab.
 693 ***********************************************************************/
 694 
 695 int ads_keytab_list(const char *keytab_name)
     /* [<][>][^][v][top][bottom][index][help] */
 696 {
 697         krb5_error_code ret = 0;
 698         krb5_context context = NULL;
 699         krb5_keytab keytab = NULL;
 700         krb5_kt_cursor cursor;
 701         krb5_keytab_entry kt_entry;
 702 
 703         ZERO_STRUCT(kt_entry);
 704         ZERO_STRUCT(cursor);
 705 
 706         initialize_krb5_error_table();
 707         ret = krb5_init_context(&context);
 708         if (ret) {
 709                 DEBUG(1,("ads_keytab_list: could not krb5_init_context: %s\n",error_message(ret)));
 710                 return ret;
 711         }
 712 
 713         ret = smb_krb5_open_keytab(context, keytab_name, False, &keytab);
 714         if (ret) {
 715                 DEBUG(1,("ads_keytab_list: smb_krb5_open_keytab failed (%s)\n", error_message(ret)));
 716                 goto out;
 717         }
 718 
 719         ret = krb5_kt_start_seq_get(context, keytab, &cursor);
 720         if (ret) {
 721                 goto out;
 722         }
 723 
 724         printf("Vno  Type        Principal\n");
 725 
 726         while (krb5_kt_next_entry(context, keytab, &kt_entry, &cursor) == 0) {
 727         
 728                 char *princ_s = NULL;
 729                 char *etype_s = NULL;
 730                 krb5_enctype enctype = 0;
 731 
 732                 ret = smb_krb5_unparse_name(talloc_tos(), context, kt_entry.principal, &princ_s);
 733                 if (ret) {
 734                         goto out;
 735                 }
 736 
 737                 enctype = smb_get_enctype_from_kt_entry(&kt_entry);
 738 
 739                 ret = smb_krb5_enctype_to_string(context, enctype, &etype_s);
 740                 if (ret) {
 741                         if (asprintf(&etype_s, "UNKNOWN: %d\n", enctype) == -1)
 742                         {
 743                                 TALLOC_FREE(princ_s);
 744                                 goto out;
 745                         }
 746                 }
 747 
 748                 printf("%3d  %s\t\t %s\n", kt_entry.vno, etype_s, princ_s);
 749 
 750                 TALLOC_FREE(princ_s);
 751                 SAFE_FREE(etype_s);
 752 
 753                 ret = smb_krb5_kt_free_entry(context, &kt_entry);
 754                 if (ret) {
 755                         goto out;
 756                 }
 757         }
 758 
 759         ret = krb5_kt_end_seq_get(context, keytab, &cursor);
 760         if (ret) {
 761                 goto out;
 762         }
 763 
 764         /* Ensure we don't double free. */
 765         ZERO_STRUCT(kt_entry);
 766         ZERO_STRUCT(cursor);
 767 out:
 768 
 769         {
 770                 krb5_keytab_entry zero_kt_entry;
 771                 ZERO_STRUCT(zero_kt_entry);
 772                 if (memcmp(&zero_kt_entry, &kt_entry, sizeof(krb5_keytab_entry))) {
 773                         smb_krb5_kt_free_entry(context, &kt_entry);
 774                 }
 775         }
 776         {
 777                 krb5_kt_cursor zero_csr;
 778                 ZERO_STRUCT(zero_csr);
 779                 if ((memcmp(&cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && keytab) {
 780                         krb5_kt_end_seq_get(context, keytab, &cursor);  
 781                 }
 782         }
 783 
 784         if (keytab) {
 785                 krb5_kt_close(context, keytab);
 786         }
 787         if (context) {
 788                 krb5_free_context(context);
 789         }
 790         return ret;
 791 }
 792 
 793 #endif /* HAVE_KRB5 */

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