root/source4/auth/credentials/credentials_krb5.c

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

DEFINITIONS

This source file includes following definitions.
  1. cli_credentials_get_krb5_context
  2. cli_credentials_set_krb5_context
  3. cli_credentials_set_from_ccache
  4. free_mccache
  5. free_dccache
  6. cli_credentials_set_ccache
  7. cli_credentials_new_ccache
  8. cli_credentials_get_ccache
  9. cli_credentials_invalidate_client_gss_creds
  10. cli_credentials_invalidate_ccache
  11. free_gssapi_creds
  12. cli_credentials_get_client_gss_creds
  13. cli_credentials_set_client_gss_creds
  14. cli_credentials_get_keytab
  15. cli_credentials_set_keytab_name
  16. cli_credentials_update_keytab
  17. cli_credentials_get_server_gss_creds
  18. cli_credentials_set_kvno
  19. cli_credentials_get_kvno
  20. cli_credentials_get_enctype_strings
  21. cli_credentials_get_salt_principal
  22. cli_credentials_set_salt_principal

   1 /* 
   2    Unix SMB/CIFS implementation.
   3 
   4    Handle user credentials (as regards krb5)
   5 
   6    Copyright (C) Jelmer Vernooij 2005
   7    Copyright (C) Tim Potter 2001
   8    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
   9    
  10    This program is free software; you can redistribute it and/or modify
  11    it under the terms of the GNU General Public License as published by
  12    the Free Software Foundation; either version 3 of the License, or
  13    (at your option) any later version.
  14    
  15    This program is distributed in the hope that it will be useful,
  16    but WITHOUT ANY WARRANTY; without even the implied warranty of
  17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18    GNU General Public License for more details.
  19    
  20    You should have received a copy of the GNU General Public License
  21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  22 */
  23 
  24 #include "includes.h"
  25 #include "system/kerberos.h"
  26 #include "auth/kerberos/kerberos.h"
  27 #include "auth/credentials/credentials.h"
  28 #include "auth/credentials/credentials_proto.h"
  29 #include "auth/credentials/credentials_krb5.h"
  30 #include "param/param.h"
  31 
  32 _PUBLIC_ int cli_credentials_get_krb5_context(struct cli_credentials *cred, 
     /* [<][>][^][v][top][bottom][index][help] */
  33                                               struct tevent_context *event_ctx,
  34                                      struct loadparm_context *lp_ctx,
  35                                      struct smb_krb5_context **smb_krb5_context) 
  36 {
  37         int ret;
  38         if (cred->smb_krb5_context) {
  39                 *smb_krb5_context = cred->smb_krb5_context;
  40                 return 0;
  41         }
  42 
  43         ret = smb_krb5_init_context(cred, event_ctx, lp_ctx, &cred->smb_krb5_context);
  44         if (ret) {
  45                 cred->smb_krb5_context = NULL;
  46                 return ret;
  47         }
  48         *smb_krb5_context = cred->smb_krb5_context;
  49         return 0;
  50 }
  51 
  52 /* This needs to be called directly after the cli_credentials_init(),
  53  * otherwise we might have problems with the krb5 context already
  54  * being here.
  55  */
  56 _PUBLIC_ NTSTATUS cli_credentials_set_krb5_context(struct cli_credentials *cred, 
     /* [<][>][^][v][top][bottom][index][help] */
  57                                           struct smb_krb5_context *smb_krb5_context)
  58 {
  59         if (!talloc_reference(cred, smb_krb5_context)) {
  60                 return NT_STATUS_NO_MEMORY;
  61         }
  62         cred->smb_krb5_context = smb_krb5_context;
  63         return NT_STATUS_OK;
  64 }
  65 
  66 static int cli_credentials_set_from_ccache(struct cli_credentials *cred, 
     /* [<][>][^][v][top][bottom][index][help] */
  67                                     struct ccache_container *ccache,
  68                                     enum credentials_obtained obtained)
  69 {
  70         
  71         krb5_principal princ;
  72         krb5_error_code ret;
  73         char *name;
  74         char **realm;
  75 
  76         if (cred->ccache_obtained > obtained) {
  77                 return 0;
  78         }
  79 
  80         ret = krb5_cc_get_principal(ccache->smb_krb5_context->krb5_context, 
  81                                     ccache->ccache, &princ);
  82 
  83         if (ret) {
  84                 char *err_mess = smb_get_krb5_error_message(ccache->smb_krb5_context->krb5_context, 
  85                                                             ret, cred);
  86                 DEBUG(1,("failed to get principal from ccache: %s\n", 
  87                          err_mess));
  88                 talloc_free(err_mess);
  89                 return ret;
  90         }
  91         
  92         ret = krb5_unparse_name(ccache->smb_krb5_context->krb5_context, princ, &name);
  93         if (ret) {
  94                 char *err_mess = smb_get_krb5_error_message(ccache->smb_krb5_context->krb5_context, ret, cred);
  95                 DEBUG(1,("failed to unparse principal from ccache: %s\n", 
  96                          err_mess));
  97                 talloc_free(err_mess);
  98                 return ret;
  99         }
 100 
 101         realm = krb5_princ_realm(ccache->smb_krb5_context->krb5_context, princ);
 102 
 103         cli_credentials_set_principal(cred, name, obtained);
 104 
 105         free(name);
 106 
 107         krb5_free_principal(ccache->smb_krb5_context->krb5_context, princ);
 108 
 109         /* set the ccache_obtained here, as it just got set to UNINITIALISED by the calls above */
 110         cred->ccache_obtained = obtained;
 111 
 112         return 0;
 113 }
 114 
 115 /* Free a memory ccache */
 116 static int free_mccache(struct ccache_container *ccc)
     /* [<][>][^][v][top][bottom][index][help] */
 117 {
 118         krb5_cc_destroy(ccc->smb_krb5_context->krb5_context, ccc->ccache);
 119 
 120         return 0;
 121 }
 122 
 123 /* Free a disk-based ccache */
 124 static int free_dccache(struct ccache_container *ccc) {
     /* [<][>][^][v][top][bottom][index][help] */
 125         krb5_cc_close(ccc->smb_krb5_context->krb5_context, ccc->ccache);
 126 
 127         return 0;
 128 }
 129 
 130 _PUBLIC_ int cli_credentials_set_ccache(struct cli_credentials *cred, 
     /* [<][>][^][v][top][bottom][index][help] */
 131                                         struct tevent_context *event_ctx,
 132                                struct loadparm_context *lp_ctx,
 133                                const char *name, 
 134                                enum credentials_obtained obtained)
 135 {
 136         krb5_error_code ret;
 137         krb5_principal princ;
 138         struct ccache_container *ccc;
 139         if (cred->ccache_obtained > obtained) {
 140                 return 0;
 141         }
 142 
 143         ccc = talloc(cred, struct ccache_container);
 144         if (!ccc) {
 145                 return ENOMEM;
 146         }
 147 
 148         ret = cli_credentials_get_krb5_context(cred, event_ctx, lp_ctx, 
 149                                                &ccc->smb_krb5_context);
 150         if (ret) {
 151                 talloc_free(ccc);
 152                 return ret;
 153         }
 154         if (!talloc_reference(ccc, ccc->smb_krb5_context)) {
 155                 talloc_free(ccc);
 156                 return ENOMEM;
 157         }
 158 
 159         if (name) {
 160                 ret = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context, name, &ccc->ccache);
 161                 if (ret) {
 162                         DEBUG(1,("failed to read krb5 ccache: %s: %s\n", 
 163                                  name, 
 164                                  smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context, ret, ccc)));
 165                         talloc_free(ccc);
 166                         return ret;
 167                 }
 168         } else {
 169                 ret = krb5_cc_default(ccc->smb_krb5_context->krb5_context, &ccc->ccache);
 170                 if (ret) {
 171                         DEBUG(3,("failed to read default krb5 ccache: %s\n", 
 172                                  smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context, ret, ccc)));
 173                         talloc_free(ccc);
 174                         return ret;
 175                 }
 176         }
 177 
 178         talloc_set_destructor(ccc, free_dccache);
 179 
 180         ret = krb5_cc_get_principal(ccc->smb_krb5_context->krb5_context, ccc->ccache, &princ);
 181 
 182         if (ret) {
 183                 DEBUG(3,("failed to get principal from default ccache: %s\n", 
 184                          smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context, ret, ccc)));
 185                 talloc_free(ccc);               
 186                 return ret;
 187         }
 188 
 189         krb5_free_principal(ccc->smb_krb5_context->krb5_context, princ);
 190 
 191         ret = cli_credentials_set_from_ccache(cred, ccc, obtained);
 192 
 193         if (ret) {
 194                 return ret;
 195         }
 196 
 197         cred->ccache = ccc;
 198         cred->ccache_obtained = obtained;
 199         talloc_steal(cred, ccc);
 200 
 201         cli_credentials_invalidate_client_gss_creds(cred, cred->ccache_obtained);
 202         return 0;
 203 }
 204 
 205 
 206 static int cli_credentials_new_ccache(struct cli_credentials *cred, 
     /* [<][>][^][v][top][bottom][index][help] */
 207                                       struct tevent_context *event_ctx,
 208                                       struct loadparm_context *lp_ctx,
 209                                       struct ccache_container **_ccc)
 210 {
 211         krb5_error_code ret;
 212         struct ccache_container *ccc = talloc(cred, struct ccache_container);
 213         char *ccache_name;
 214         if (!ccc) {
 215                 return ENOMEM;
 216         }
 217 
 218         ccache_name = talloc_asprintf(ccc, "MEMORY:%p", 
 219                                       ccc);
 220 
 221         if (!ccache_name) {
 222                 talloc_free(ccc);
 223                 return ENOMEM;
 224         }
 225 
 226         ret = cli_credentials_get_krb5_context(cred, event_ctx, lp_ctx, 
 227                                                &ccc->smb_krb5_context);
 228         if (ret) {
 229                 talloc_free(ccc);
 230                 return ret;
 231         }
 232         if (!talloc_reference(ccc, ccc->smb_krb5_context)) {
 233                 talloc_free(ccc);
 234                 return ENOMEM;
 235         }
 236 
 237         ret = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context, ccache_name, 
 238                               &ccc->ccache);
 239         if (ret) {
 240                 DEBUG(1,("failed to generate a new krb5 ccache (%s): %s\n", 
 241                          ccache_name,
 242                          smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context, ret, ccc)));
 243                 talloc_free(ccache_name);
 244                 talloc_free(ccc);
 245                 return ret;
 246         }
 247 
 248         talloc_set_destructor(ccc, free_mccache);
 249 
 250         talloc_free(ccache_name);
 251 
 252         *_ccc = ccc;
 253 
 254         return ret;
 255 }
 256 
 257 _PUBLIC_ int cli_credentials_get_ccache(struct cli_credentials *cred, 
     /* [<][>][^][v][top][bottom][index][help] */
 258                                         struct tevent_context *event_ctx,
 259                                struct loadparm_context *lp_ctx,
 260                                struct ccache_container **ccc)
 261 {
 262         krb5_error_code ret;
 263         
 264         if (cred->machine_account_pending) {
 265                 cli_credentials_set_machine_account(cred, lp_ctx);
 266         }
 267 
 268         if (cred->ccache_obtained >= cred->ccache_threshold && 
 269             cred->ccache_obtained > CRED_UNINITIALISED) {
 270                 *ccc = cred->ccache;
 271                 return 0;
 272         }
 273         if (cli_credentials_is_anonymous(cred)) {
 274                 return EINVAL;
 275         }
 276 
 277         ret = cli_credentials_new_ccache(cred, event_ctx, lp_ctx, ccc);
 278         if (ret) {
 279                 return ret;
 280         }
 281 
 282         ret = kinit_to_ccache(cred, cred, (*ccc)->smb_krb5_context, (*ccc)->ccache);
 283         if (ret) {
 284                 return ret;
 285         }
 286 
 287         ret = cli_credentials_set_from_ccache(cred, *ccc, 
 288                                               (MAX(MAX(cred->principal_obtained, 
 289                                                        cred->username_obtained), 
 290                                                    cred->password_obtained)));
 291         
 292         cred->ccache = *ccc;
 293         cred->ccache_obtained = cred->principal_obtained;
 294         if (ret) {
 295                 return ret;
 296         }
 297         cli_credentials_invalidate_client_gss_creds(cred, cred->ccache_obtained);
 298         return ret;
 299 }
 300 
 301 void cli_credentials_invalidate_client_gss_creds(struct cli_credentials *cred, 
     /* [<][>][^][v][top][bottom][index][help] */
 302                                                  enum credentials_obtained obtained)
 303 {
 304         /* If the caller just changed the username/password etc, then
 305          * any cached credentials are now invalid */
 306         if (obtained >= cred->client_gss_creds_obtained) {
 307                 if (cred->client_gss_creds_obtained > CRED_UNINITIALISED) {
 308                         talloc_unlink(cred, cred->client_gss_creds);
 309                         cred->client_gss_creds = NULL;
 310                 }
 311                 cred->client_gss_creds_obtained = CRED_UNINITIALISED;
 312         }
 313         /* Now that we know that the data is 'this specified', then
 314          * don't allow something less 'known' to be returned as a
 315          * ccache.  Ie, if the username is on the commmand line, we
 316          * don't want to later guess to use a file-based ccache */
 317         if (obtained > cred->client_gss_creds_threshold) {
 318                 cred->client_gss_creds_threshold = obtained;
 319         }
 320 }
 321 
 322 _PUBLIC_ void cli_credentials_invalidate_ccache(struct cli_credentials *cred, 
     /* [<][>][^][v][top][bottom][index][help] */
 323                                        enum credentials_obtained obtained)
 324 {
 325         /* If the caller just changed the username/password etc, then
 326          * any cached credentials are now invalid */
 327         if (obtained >= cred->ccache_obtained) {
 328                 if (cred->ccache_obtained > CRED_UNINITIALISED) {
 329                         talloc_unlink(cred, cred->ccache);
 330                         cred->ccache = NULL;
 331                 }
 332                 cred->ccache_obtained = CRED_UNINITIALISED;
 333         }
 334         /* Now that we know that the data is 'this specified', then
 335          * don't allow something less 'known' to be returned as a
 336          * ccache.  Ie, if the username is on the commmand line, we
 337          * don't want to later guess to use a file-based ccache */
 338         if (obtained > cred->ccache_threshold) {
 339                 cred->ccache_threshold  = obtained;
 340         }
 341 
 342         cli_credentials_invalidate_client_gss_creds(cred, 
 343                                                     obtained);
 344 }
 345 
 346 static int free_gssapi_creds(struct gssapi_creds_container *gcc)
     /* [<][>][^][v][top][bottom][index][help] */
 347 {
 348         OM_uint32 min_stat, maj_stat;
 349         maj_stat = gss_release_cred(&min_stat, &gcc->creds);
 350         return 0;
 351 }
 352 
 353 _PUBLIC_ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred, 
     /* [<][>][^][v][top][bottom][index][help] */
 354                                          struct tevent_context *event_ctx,
 355                                          struct loadparm_context *lp_ctx,
 356                                          struct gssapi_creds_container **_gcc) 
 357 {
 358         int ret = 0;
 359         OM_uint32 maj_stat, min_stat;
 360         struct gssapi_creds_container *gcc;
 361         struct ccache_container *ccache;
 362         gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER;
 363         krb5_enctype *etypes = NULL;
 364 
 365         if (cred->client_gss_creds_obtained >= cred->client_gss_creds_threshold && 
 366             cred->client_gss_creds_obtained > CRED_UNINITIALISED) {
 367                 *_gcc = cred->client_gss_creds;
 368                 return 0;
 369         }
 370 
 371         ret = cli_credentials_get_ccache(cred, event_ctx, lp_ctx, 
 372                                          &ccache);
 373         if (ret) {
 374                 DEBUG(1, ("Failed to get CCACHE for GSSAPI client: %s\n", error_message(ret)));
 375                 return ret;
 376         }
 377 
 378         gcc = talloc(cred, struct gssapi_creds_container);
 379         if (!gcc) {
 380                 return ENOMEM;
 381         }
 382 
 383         maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL, 
 384                                         &gcc->creds);
 385         if (maj_stat) {
 386                 talloc_free(gcc);
 387                 if (min_stat) {
 388                         ret = min_stat;
 389                 } else {
 390                         ret = EINVAL;
 391                 }
 392                 return ret;
 393         }
 394 
 395         /*
 396          * transfer the enctypes from the smb_krb5_context to the gssapi layer
 397          *
 398          * We use 'our' smb_krb5_context to do the AS-REQ and it is possible
 399          * to configure the enctypes via the krb5.conf.
 400          *
 401          * And the gss_init_sec_context() creates it's own krb5_context and
 402          * the TGS-REQ had all enctypes in it and only the ones configured
 403          * and used for the AS-REQ, so it wasn't possible to disable the usage
 404          * of AES keys.
 405          */
 406         min_stat = krb5_get_default_in_tkt_etypes(ccache->smb_krb5_context->krb5_context,
 407                                                   &etypes);
 408         if (min_stat == 0) {
 409                 OM_uint32 num_ktypes;
 410 
 411                 for (num_ktypes = 0; etypes[num_ktypes]; num_ktypes++);
 412 
 413                 maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, gcc->creds,
 414                                                            num_ktypes, etypes);
 415                 krb5_xfree (etypes);
 416                 if (maj_stat) {
 417                         talloc_free(gcc);
 418                         if (min_stat) {
 419                                 ret = min_stat;
 420                         } else {
 421                                 ret = EINVAL;
 422                         }
 423                         return ret;
 424                 }
 425         }
 426 
 427         /* don't force GSS_C_CONF_FLAG and GSS_C_INTEG_FLAG */
 428         maj_stat = gss_set_cred_option(&min_stat, &gcc->creds,
 429                                        GSS_KRB5_CRED_NO_CI_FLAGS_X,
 430                                        &empty_buffer);
 431         if (maj_stat) {
 432                 talloc_free(gcc);
 433                 if (min_stat) {
 434                         ret = min_stat;
 435                 } else {
 436                         ret = EINVAL;
 437                 }
 438                 return ret;
 439         }
 440 
 441         cred->client_gss_creds_obtained = cred->ccache_obtained;
 442         talloc_set_destructor(gcc, free_gssapi_creds);
 443         cred->client_gss_creds = gcc;
 444         *_gcc = gcc;
 445         return 0;
 446 }
 447 
 448 /**
 449    Set a gssapi cred_id_t into the credentials system. (Client case)
 450 
 451    This grabs the credentials both 'intact' and getting the krb5
 452    ccache out of it.  This routine can be generalised in future for
 453    the case where we deal with GSSAPI mechs other than krb5.  
 454 
 455    On sucess, the caller must not free gssapi_cred, as it now belongs
 456    to the credentials system.
 457 */
 458 
 459  int cli_credentials_set_client_gss_creds(struct cli_credentials *cred, 
     /* [<][>][^][v][top][bottom][index][help] */
 460                                           struct tevent_context *event_ctx,
 461                                           struct loadparm_context *lp_ctx,
 462                                           gss_cred_id_t gssapi_cred,
 463                                           enum credentials_obtained obtained) 
 464 {
 465         int ret;
 466         OM_uint32 maj_stat, min_stat;
 467         struct ccache_container *ccc;
 468         struct gssapi_creds_container *gcc;
 469         if (cred->client_gss_creds_obtained > obtained) {
 470                 return 0;
 471         }
 472 
 473         gcc = talloc(cred, struct gssapi_creds_container);
 474         if (!gcc) {
 475                 return ENOMEM;
 476         }
 477 
 478         ret = cli_credentials_new_ccache(cred, event_ctx, lp_ctx, &ccc);
 479         if (ret != 0) {
 480                 return ret;
 481         }
 482 
 483         maj_stat = gss_krb5_copy_ccache(&min_stat, 
 484                                         gssapi_cred, ccc->ccache);
 485         if (maj_stat) {
 486                 if (min_stat) {
 487                         ret = min_stat;
 488                 } else {
 489                         ret = EINVAL;
 490                 }
 491         }
 492 
 493         if (ret == 0) {
 494                 ret = cli_credentials_set_from_ccache(cred, ccc, obtained);
 495         }
 496         cred->ccache = ccc;
 497         cred->ccache_obtained = obtained;
 498         if (ret == 0) {
 499                 gcc->creds = gssapi_cred;
 500                 talloc_set_destructor(gcc, free_gssapi_creds);
 501                 
 502                 /* set the clinet_gss_creds_obtained here, as it just 
 503                    got set to UNINITIALISED by the calls above */
 504                 cred->client_gss_creds_obtained = obtained;
 505                 cred->client_gss_creds = gcc;
 506         }
 507         return ret;
 508 }
 509 
 510 /* Get the keytab (actually, a container containing the krb5_keytab)
 511  * attached to this context.  If this hasn't been done or set before,
 512  * it will be generated from the password.
 513  */
 514 _PUBLIC_ int cli_credentials_get_keytab(struct cli_credentials *cred, 
     /* [<][>][^][v][top][bottom][index][help] */
 515                                         struct tevent_context *event_ctx,
 516                                struct loadparm_context *lp_ctx,
 517                                struct keytab_container **_ktc)
 518 {
 519         krb5_error_code ret;
 520         struct keytab_container *ktc;
 521         struct smb_krb5_context *smb_krb5_context;
 522         const char **enctype_strings;
 523         TALLOC_CTX *mem_ctx;
 524 
 525         if (cred->keytab_obtained >= (MAX(cred->principal_obtained, 
 526                                           cred->username_obtained))) {
 527                 *_ktc = cred->keytab;
 528                 return 0;
 529         }
 530 
 531         if (cli_credentials_is_anonymous(cred)) {
 532                 return EINVAL;
 533         }
 534 
 535         ret = cli_credentials_get_krb5_context(cred, event_ctx, lp_ctx, 
 536                                                &smb_krb5_context);
 537         if (ret) {
 538                 return ret;
 539         }
 540 
 541         mem_ctx = talloc_new(cred);
 542         if (!mem_ctx) {
 543                 return ENOMEM;
 544         }
 545 
 546         enctype_strings = cli_credentials_get_enctype_strings(cred);
 547         
 548         ret = smb_krb5_create_memory_keytab(mem_ctx, cred, 
 549                                             smb_krb5_context, 
 550                                             enctype_strings, &ktc);
 551         if (ret) {
 552                 talloc_free(mem_ctx);
 553                 return ret;
 554         }
 555 
 556         cred->keytab_obtained = (MAX(cred->principal_obtained, 
 557                                      cred->username_obtained));
 558 
 559         talloc_steal(cred, ktc);
 560         cred->keytab = ktc;
 561         *_ktc = cred->keytab;
 562         talloc_free(mem_ctx);
 563         return ret;
 564 }
 565 
 566 /* Given the name of a keytab (presumably in the format
 567  * FILE:/etc/krb5.keytab), open it and attach it */
 568 
 569 _PUBLIC_ int cli_credentials_set_keytab_name(struct cli_credentials *cred, 
     /* [<][>][^][v][top][bottom][index][help] */
 570                                              struct tevent_context *event_ctx,
 571                                     struct loadparm_context *lp_ctx,
 572                                     const char *keytab_name, 
 573                                     enum credentials_obtained obtained) 
 574 {
 575         krb5_error_code ret;
 576         struct keytab_container *ktc;
 577         struct smb_krb5_context *smb_krb5_context;
 578         TALLOC_CTX *mem_ctx;
 579 
 580         if (cred->keytab_obtained >= obtained) {
 581                 return 0;
 582         }
 583 
 584         ret = cli_credentials_get_krb5_context(cred, event_ctx, lp_ctx, &smb_krb5_context);
 585         if (ret) {
 586                 return ret;
 587         }
 588 
 589         mem_ctx = talloc_new(cred);
 590         if (!mem_ctx) {
 591                 return ENOMEM;
 592         }
 593 
 594         ret = smb_krb5_open_keytab(mem_ctx, smb_krb5_context, 
 595                                    keytab_name, &ktc);
 596         if (ret) {
 597                 return ret;
 598         }
 599 
 600         cred->keytab_obtained = obtained;
 601 
 602         talloc_steal(cred, ktc);
 603         cred->keytab = ktc;
 604         talloc_free(mem_ctx);
 605 
 606         return ret;
 607 }
 608 
 609 _PUBLIC_ int cli_credentials_update_keytab(struct cli_credentials *cred, 
     /* [<][>][^][v][top][bottom][index][help] */
 610                                            struct tevent_context *event_ctx,
 611                                   struct loadparm_context *lp_ctx) 
 612 {
 613         krb5_error_code ret;
 614         struct keytab_container *ktc;
 615         struct smb_krb5_context *smb_krb5_context;
 616         const char **enctype_strings;
 617         TALLOC_CTX *mem_ctx;
 618         
 619         mem_ctx = talloc_new(cred);
 620         if (!mem_ctx) {
 621                 return ENOMEM;
 622         }
 623 
 624         ret = cli_credentials_get_krb5_context(cred, event_ctx, lp_ctx, &smb_krb5_context);
 625         if (ret) {
 626                 talloc_free(mem_ctx);
 627                 return ret;
 628         }
 629 
 630         enctype_strings = cli_credentials_get_enctype_strings(cred);
 631         
 632         ret = cli_credentials_get_keytab(cred, event_ctx, lp_ctx, &ktc);
 633         if (ret != 0) {
 634                 talloc_free(mem_ctx);
 635                 return ret;
 636         }
 637 
 638         ret = smb_krb5_update_keytab(mem_ctx, cred, smb_krb5_context, enctype_strings, ktc);
 639 
 640         talloc_free(mem_ctx);
 641         return ret;
 642 }
 643 
 644 /* Get server gss credentials (in gsskrb5, this means the keytab) */
 645 
 646 _PUBLIC_ int cli_credentials_get_server_gss_creds(struct cli_credentials *cred, 
     /* [<][>][^][v][top][bottom][index][help] */
 647                                                   struct tevent_context *event_ctx,
 648                                          struct loadparm_context *lp_ctx,
 649                                          struct gssapi_creds_container **_gcc) 
 650 {
 651         int ret = 0;
 652         OM_uint32 maj_stat, min_stat;
 653         struct gssapi_creds_container *gcc;
 654         struct keytab_container *ktc;
 655         struct smb_krb5_context *smb_krb5_context;
 656         TALLOC_CTX *mem_ctx;
 657         krb5_principal princ;
 658 
 659         if (cred->server_gss_creds_obtained >= (MAX(cred->keytab_obtained, 
 660                                                     MAX(cred->principal_obtained, 
 661                                                         cred->username_obtained)))) {
 662                 *_gcc = cred->server_gss_creds;
 663                 return 0;
 664         }
 665 
 666         ret = cli_credentials_get_krb5_context(cred, event_ctx, lp_ctx, &smb_krb5_context);
 667         if (ret) {
 668                 return ret;
 669         }
 670 
 671         ret = cli_credentials_get_keytab(cred, event_ctx, lp_ctx, &ktc);
 672         if (ret) {
 673                 DEBUG(1, ("Failed to get keytab for GSSAPI server: %s\n", error_message(ret)));
 674                 return ret;
 675         }
 676 
 677         mem_ctx = talloc_new(cred);
 678         if (!mem_ctx) {
 679                 return ENOMEM;
 680         }
 681 
 682         ret = principal_from_credentials(mem_ctx, cred, smb_krb5_context, &princ);
 683         if (ret) {
 684                 DEBUG(1,("cli_credentials_get_server_gss_creds: makeing krb5 principal failed (%s)\n",
 685                          smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
 686                                                     ret, mem_ctx)));
 687                 talloc_free(mem_ctx);
 688                 return ret;
 689         }
 690 
 691         gcc = talloc(cred, struct gssapi_creds_container);
 692         if (!gcc) {
 693                 talloc_free(mem_ctx);
 694                 return ENOMEM;
 695         }
 696 
 697         /* This creates a GSSAPI cred_id_t with the principal and keytab set */
 698         maj_stat = gss_krb5_import_cred(&min_stat, NULL, princ, ktc->keytab, 
 699                                         &gcc->creds);
 700         if (maj_stat) {
 701                 if (min_stat) {
 702                         ret = min_stat;
 703                 } else {
 704                         ret = EINVAL;
 705                 }
 706         }
 707         if (ret == 0) {
 708                 cred->server_gss_creds_obtained = cred->keytab_obtained;
 709                 talloc_set_destructor(gcc, free_gssapi_creds);
 710                 cred->server_gss_creds = gcc;
 711                 *_gcc = gcc;
 712         }
 713         talloc_free(mem_ctx);
 714         return ret;
 715 }
 716 
 717 /** 
 718  * Set Kerberos KVNO
 719  */
 720 
 721 _PUBLIC_ void cli_credentials_set_kvno(struct cli_credentials *cred,
     /* [<][>][^][v][top][bottom][index][help] */
 722                               int kvno)
 723 {
 724         cred->kvno = kvno;
 725 }
 726 
 727 /**
 728  * Return Kerberos KVNO
 729  */
 730 
 731 _PUBLIC_ int cli_credentials_get_kvno(struct cli_credentials *cred)
     /* [<][>][^][v][top][bottom][index][help] */
 732 {
 733         return cred->kvno;
 734 }
 735 
 736 
 737 const char **cli_credentials_get_enctype_strings(struct cli_credentials *cred) 
     /* [<][>][^][v][top][bottom][index][help] */
 738 {
 739         /* If this is ever made user-configurable, we need to add code
 740          * to remove/hide the other entries from the generated
 741          * keytab */
 742         static const char *default_enctypes[] = {
 743                 "des-cbc-md5",
 744                 "aes256-cts-hmac-sha1-96",
 745                 "des3-cbc-sha1",
 746                 "arcfour-hmac-md5",
 747                 NULL
 748         };
 749         return default_enctypes;
 750 }
 751 
 752 const char *cli_credentials_get_salt_principal(struct cli_credentials *cred) 
     /* [<][>][^][v][top][bottom][index][help] */
 753 {
 754         return cred->salt_principal;
 755 }
 756 
 757 _PUBLIC_ void cli_credentials_set_salt_principal(struct cli_credentials *cred, const char *principal) 
     /* [<][>][^][v][top][bottom][index][help] */
 758 {
 759         cred->salt_principal = talloc_strdup(cred, principal);
 760 }
 761 
 762 

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