root/source3/libads/kerberos.c

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

DEFINITIONS

This source file includes following definitions.
  1. kerb_prompter
  2. smb_krb5_get_ntstatus_from_krb5_error
  3. smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt
  4. kerberos_kinit_password_ext
  5. ads_kinit_password
  6. ads_kdestroy
  7. kerberos_secrets_fetch_salting_principal
  8. kerberos_standard_des_salt
  9. des_salt_key
  10. kerberos_secrets_store_des_salt
  11. kerberos_secrets_fetch_des_salt
  12. kerberos_get_default_realm_from_ccache
  13. kerberos_fetch_salt_princ_for_host_princ
  14. kerberos_secrets_store_salting_principal
  15. kerberos_kinit_password
  16. print_kdc_line
  17. get_kdc_ip_string
  18. create_local_private_krb5_conf_for_domain

   1 /* 
   2    Unix SMB/CIFS implementation.
   3    kerberos utility library
   4    Copyright (C) Andrew Tridgell 2001
   5    Copyright (C) Remus Koos 2001
   6    Copyright (C) Nalin Dahyabhai <nalin@redhat.com> 2004.
   7    Copyright (C) Jeremy Allison 2004.
   8    Copyright (C) Gerald Carter 2006.
   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 
  26 #ifdef HAVE_KRB5
  27 
  28 #define DEFAULT_KRB5_PORT 88
  29 
  30 #define LIBADS_CCACHE_NAME "MEMORY:libads"
  31 
  32 /*
  33   we use a prompter to avoid a crash bug in the kerberos libs when 
  34   dealing with empty passwords
  35   this prompter is just a string copy ...
  36 */
  37 static krb5_error_code 
  38 kerb_prompter(krb5_context ctx, void *data,
     /* [<][>][^][v][top][bottom][index][help] */
  39                const char *name,
  40                const char *banner,
  41                int num_prompts,
  42                krb5_prompt prompts[])
  43 {
  44         if (num_prompts == 0) return 0;
  45 
  46         memset(prompts[0].reply->data, '\0', prompts[0].reply->length);
  47         if (prompts[0].reply->length > 0) {
  48                 if (data) {
  49                         strncpy(prompts[0].reply->data, (const char *)data,
  50                                 prompts[0].reply->length-1);
  51                         prompts[0].reply->length = strlen(prompts[0].reply->data);
  52                 } else {
  53                         prompts[0].reply->length = 0;
  54                 }
  55         }
  56         return 0;
  57 }
  58 
  59  static bool smb_krb5_get_ntstatus_from_krb5_error(krb5_error *error,
     /* [<][>][^][v][top][bottom][index][help] */
  60                                                    NTSTATUS *nt_status)
  61 {
  62         DATA_BLOB edata;
  63         DATA_BLOB unwrapped_edata;
  64         TALLOC_CTX *mem_ctx;
  65         struct KRB5_EDATA_NTSTATUS parsed_edata;
  66         enum ndr_err_code ndr_err;
  67 
  68 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
  69         edata = data_blob(error->e_data->data, error->e_data->length);
  70 #else
  71         edata = data_blob(error->e_data.data, error->e_data.length);
  72 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
  73 
  74 #ifdef DEVELOPER
  75         dump_data(10, edata.data, edata.length);
  76 #endif /* DEVELOPER */
  77 
  78         mem_ctx = talloc_init("smb_krb5_get_ntstatus_from_krb5_error");
  79         if (mem_ctx == NULL) {
  80                 data_blob_free(&edata);
  81                 return False;
  82         }
  83 
  84         if (!unwrap_edata_ntstatus(mem_ctx, &edata, &unwrapped_edata)) {
  85                 data_blob_free(&edata);
  86                 TALLOC_FREE(mem_ctx);
  87                 return False;
  88         }
  89 
  90         data_blob_free(&edata);
  91 
  92         ndr_err = ndr_pull_struct_blob_all(&unwrapped_edata, mem_ctx, NULL,
  93                         &parsed_edata,
  94                         (ndr_pull_flags_fn_t)ndr_pull_KRB5_EDATA_NTSTATUS);
  95         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
  96                 data_blob_free(&unwrapped_edata);
  97                 TALLOC_FREE(mem_ctx);
  98                 return False;
  99         }
 100 
 101         data_blob_free(&unwrapped_edata);
 102 
 103         if (nt_status) {
 104                 *nt_status = parsed_edata.ntstatus;
 105         }
 106 
 107         TALLOC_FREE(mem_ctx);
 108 
 109         return True;
 110 }
 111 
 112  static bool smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(krb5_context ctx, 
     /* [<][>][^][v][top][bottom][index][help] */
 113                                                                   krb5_get_init_creds_opt *opt, 
 114                                                                   NTSTATUS *nt_status)
 115 {
 116         bool ret = False;
 117         krb5_error *error = NULL;
 118 
 119 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR
 120         ret = krb5_get_init_creds_opt_get_error(ctx, opt, &error);
 121         if (ret) {
 122                 DEBUG(1,("krb5_get_init_creds_opt_get_error gave: %s\n", 
 123                         error_message(ret)));
 124                 return False;
 125         }
 126 #endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR */
 127 
 128         if (!error) {
 129                 DEBUG(1,("no krb5_error\n"));
 130                 return False;
 131         }
 132 
 133 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
 134         if (!error->e_data) {
 135 #else
 136         if (error->e_data.data == NULL) {
 137 #endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
 138                 DEBUG(1,("no edata in krb5_error\n")); 
 139                 krb5_free_error(ctx, error);
 140                 return False;
 141         }
 142 
 143         ret = smb_krb5_get_ntstatus_from_krb5_error(error, nt_status);
 144 
 145         krb5_free_error(ctx, error);
 146 
 147         return ret;
 148 }
 149 
 150 /*
 151   simulate a kinit, putting the tgt in the given cache location. If cache_name == NULL
 152   place in default cache location.
 153   remus@snapserver.com
 154 */
 155 int kerberos_kinit_password_ext(const char *principal,
     /* [<][>][^][v][top][bottom][index][help] */
 156                                 const char *password,
 157                                 int time_offset,
 158                                 time_t *expire_time,
 159                                 time_t *renew_till_time,
 160                                 const char *cache_name,
 161                                 bool request_pac,
 162                                 bool add_netbios_addr,
 163                                 time_t renewable_time,
 164                                 NTSTATUS *ntstatus)
 165 {
 166         krb5_context ctx = NULL;
 167         krb5_error_code code = 0;
 168         krb5_ccache cc = NULL;
 169         krb5_principal me = NULL;
 170         krb5_creds my_creds;
 171         krb5_get_init_creds_opt *opt = NULL;
 172         smb_krb5_addresses *addr = NULL;
 173 
 174         ZERO_STRUCT(my_creds);
 175 
 176         initialize_krb5_error_table();
 177         if ((code = krb5_init_context(&ctx)))
 178                 goto out;
 179 
 180         if (time_offset != 0) {
 181                 krb5_set_real_time(ctx, time(NULL) + time_offset, 0);
 182         }
 183 
 184         DEBUG(10,("kerberos_kinit_password: as %s using [%s] as ccache and config [%s]\n",
 185                         principal,
 186                         cache_name ? cache_name: krb5_cc_default_name(ctx),
 187                         getenv("KRB5_CONFIG")));
 188 
 189         if ((code = krb5_cc_resolve(ctx, cache_name ? cache_name : krb5_cc_default_name(ctx), &cc))) {
 190                 goto out;
 191         }
 192         
 193         if ((code = smb_krb5_parse_name(ctx, principal, &me))) {
 194                 goto out;
 195         }
 196 
 197         if ((code = smb_krb5_get_init_creds_opt_alloc(ctx, &opt))) {
 198                 goto out;
 199         }
 200 
 201         krb5_get_init_creds_opt_set_renew_life(opt, renewable_time);
 202         krb5_get_init_creds_opt_set_forwardable(opt, True);
 203 #if 0
 204         /* insane testing */
 205         krb5_get_init_creds_opt_set_tkt_life(opt, 60);
 206 #endif
 207 
 208 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
 209         if (request_pac) {
 210                 if ((code = krb5_get_init_creds_opt_set_pac_request(ctx, opt, (krb5_boolean)request_pac))) {
 211                         goto out;
 212                 }
 213         }
 214 #endif
 215         if (add_netbios_addr) {
 216                 if ((code = smb_krb5_gen_netbios_krb5_address(&addr))) {
 217                         goto out;
 218                 }
 219                 krb5_get_init_creds_opt_set_address_list(opt, addr->addrs);
 220         }
 221 
 222         if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, CONST_DISCARD(char *,password), 
 223                                                  kerb_prompter, CONST_DISCARD(char *,password),
 224                                                  0, NULL, opt))) {
 225                 goto out;
 226         }
 227 
 228         if ((code = krb5_cc_initialize(ctx, cc, me))) {
 229                 goto out;
 230         }
 231         
 232         if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
 233                 goto out;
 234         }
 235 
 236         if (expire_time) {
 237                 *expire_time = (time_t) my_creds.times.endtime;
 238         }
 239 
 240         if (renew_till_time) {
 241                 *renew_till_time = (time_t) my_creds.times.renew_till;
 242         }
 243  out:
 244         if (ntstatus) {
 245 
 246                 NTSTATUS status;
 247 
 248                 /* fast path */
 249                 if (code == 0) {
 250                         *ntstatus = NT_STATUS_OK;
 251                         goto cleanup;
 252                 }
 253 
 254                 /* try to get ntstatus code out of krb5_error when we have it
 255                  * inside the krb5_get_init_creds_opt - gd */
 256 
 257                 if (opt && smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(ctx, opt, &status)) {
 258                         *ntstatus = status;
 259                         goto cleanup;
 260                 }
 261 
 262                 /* fall back to self-made-mapping */
 263                 *ntstatus = krb5_to_nt_status(code);
 264         }
 265 
 266  cleanup:
 267         krb5_free_cred_contents(ctx, &my_creds);
 268         if (me) {
 269                 krb5_free_principal(ctx, me);
 270         }
 271         if (addr) {
 272                 smb_krb5_free_addresses(ctx, addr);
 273         }
 274         if (opt) {
 275                 smb_krb5_get_init_creds_opt_free(ctx, opt);
 276         }
 277         if (cc) {
 278                 krb5_cc_close(ctx, cc);
 279         }
 280         if (ctx) {
 281                 krb5_free_context(ctx);
 282         }
 283         return code;
 284 }
 285 
 286 
 287 
 288 /* run kinit to setup our ccache */
 289 int ads_kinit_password(ADS_STRUCT *ads)
     /* [<][>][^][v][top][bottom][index][help] */
 290 {
 291         char *s;
 292         int ret;
 293         const char *account_name;
 294         fstring acct_name;
 295 
 296         if (ads->auth.flags & ADS_AUTH_USER_CREDS) {
 297                 account_name = ads->auth.user_name;
 298                 goto got_accountname;
 299         }
 300 
 301         if ( IS_DC ) {
 302                 /* this will end up getting a ticket for DOMAIN@RUSTED.REA.LM */
 303                 account_name = lp_workgroup();
 304         } else {
 305                 /* always use the sAMAccountName for security = domain */
 306                 /* global_myname()$@REA.LM */
 307                 if ( lp_security() == SEC_DOMAIN ) {
 308                         fstr_sprintf( acct_name, "%s$", global_myname() );
 309                         account_name = acct_name;
 310                 }
 311                 else 
 312                         /* This looks like host/global_myname()@REA.LM */
 313                         account_name = ads->auth.user_name;
 314         }
 315 
 316  got_accountname:
 317         if (asprintf(&s, "%s@%s", account_name, ads->auth.realm) == -1) {
 318                 return KRB5_CC_NOMEM;
 319         }
 320 
 321         if (!ads->auth.password) {
 322                 SAFE_FREE(s);
 323                 return KRB5_LIBOS_CANTREADPWD;
 324         }
 325         
 326         ret = kerberos_kinit_password_ext(s, ads->auth.password, ads->auth.time_offset,
 327                         &ads->auth.tgt_expire, NULL, NULL, False, False, ads->auth.renewable, 
 328                         NULL);
 329 
 330         if (ret) {
 331                 DEBUG(0,("kerberos_kinit_password %s failed: %s\n", 
 332                          s, error_message(ret)));
 333         }
 334         SAFE_FREE(s);
 335         return ret;
 336 }
 337 
 338 int ads_kdestroy(const char *cc_name)
     /* [<][>][^][v][top][bottom][index][help] */
 339 {
 340         krb5_error_code code;
 341         krb5_context ctx = NULL;
 342         krb5_ccache cc = NULL;
 343 
 344         initialize_krb5_error_table();
 345         if ((code = krb5_init_context (&ctx))) {
 346                 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n", 
 347                         error_message(code)));
 348                 return code;
 349         }
 350   
 351         if (!cc_name) {
 352                 if ((code = krb5_cc_default(ctx, &cc))) {
 353                         krb5_free_context(ctx);
 354                         return code;
 355                 }
 356         } else {
 357                 if ((code = krb5_cc_resolve(ctx, cc_name, &cc))) {
 358                         DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
 359                                   error_message(code)));
 360                         krb5_free_context(ctx);
 361                         return code;
 362                 }
 363         }
 364 
 365         if ((code = krb5_cc_destroy (ctx, cc))) {
 366                 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n", 
 367                         error_message(code)));
 368         }
 369 
 370         krb5_free_context (ctx);
 371         return code;
 372 }
 373 
 374 /************************************************************************
 375  Routine to fetch the salting principal for a service.  Active
 376  Directory may use a non-obvious principal name to generate the salt
 377  when it determines the key to use for encrypting tickets for a service,
 378  and hopefully we detected that when we joined the domain.
 379  ************************************************************************/
 380 
 381 static char *kerberos_secrets_fetch_salting_principal(const char *service, int enctype)
     /* [<][>][^][v][top][bottom][index][help] */
 382 {
 383         char *key = NULL;
 384         char *ret = NULL;
 385 
 386         if (asprintf(&key, "%s/%s/enctype=%d",
 387                      SECRETS_SALTING_PRINCIPAL, service, enctype) == -1) {
 388                 return NULL;
 389         }
 390         ret = (char *)secrets_fetch(key, NULL);
 391         SAFE_FREE(key);
 392         return ret;
 393 }
 394 
 395 /************************************************************************
 396  Return the standard DES salt key
 397 ************************************************************************/
 398 
 399 char* kerberos_standard_des_salt( void )
     /* [<][>][^][v][top][bottom][index][help] */
 400 {
 401         fstring salt;
 402 
 403         fstr_sprintf( salt, "host/%s.%s@", global_myname(), lp_realm() );
 404         strlower_m( salt );
 405         fstrcat( salt, lp_realm() );
 406 
 407         return SMB_STRDUP( salt );
 408 }
 409 
 410 /************************************************************************
 411 ************************************************************************/
 412 
 413 static char* des_salt_key( void )
     /* [<][>][^][v][top][bottom][index][help] */
 414 {
 415         char *key;
 416 
 417         if (asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL,
 418                      lp_realm()) == -1) {
 419                 return NULL;
 420         }
 421 
 422         return key;
 423 }
 424 
 425 /************************************************************************
 426 ************************************************************************/
 427 
 428 bool kerberos_secrets_store_des_salt( const char* salt )
     /* [<][>][^][v][top][bottom][index][help] */
 429 {
 430         char* key;
 431         bool ret;
 432 
 433         if ( (key = des_salt_key()) == NULL ) {
 434                 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
 435                 return False;
 436         }
 437 
 438         if ( !salt ) {
 439                 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
 440                 secrets_delete( key );
 441                 return True;
 442         }
 443 
 444         DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
 445 
 446         ret = secrets_store( key, salt, strlen(salt)+1 );
 447 
 448         SAFE_FREE( key );
 449 
 450         return ret;
 451 }
 452 
 453 /************************************************************************
 454 ************************************************************************/
 455 
 456 char* kerberos_secrets_fetch_des_salt( void )
     /* [<][>][^][v][top][bottom][index][help] */
 457 {
 458         char *salt, *key;
 459 
 460         if ( (key = des_salt_key()) == NULL ) {
 461                 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
 462                 return False;
 463         }
 464 
 465         salt = (char*)secrets_fetch( key, NULL );
 466 
 467         SAFE_FREE( key );
 468 
 469         return salt;
 470 }
 471 
 472 /************************************************************************
 473  Routine to get the default realm from the kerberos credentials cache.
 474  Caller must free if the return value is not NULL.
 475 ************************************************************************/
 476 
 477 char *kerberos_get_default_realm_from_ccache( void )
     /* [<][>][^][v][top][bottom][index][help] */
 478 {
 479         char *realm = NULL;
 480         krb5_context ctx = NULL;
 481         krb5_ccache cc = NULL;
 482         krb5_principal princ = NULL;
 483 
 484         initialize_krb5_error_table();
 485         if (krb5_init_context(&ctx)) {
 486                 return NULL;
 487         }
 488 
 489         DEBUG(5,("kerberos_get_default_realm_from_ccache: "
 490                 "Trying to read krb5 cache: %s\n",
 491                 krb5_cc_default_name(ctx)));
 492         if (krb5_cc_default(ctx, &cc)) {
 493                 DEBUG(0,("kerberos_get_default_realm_from_ccache: "
 494                         "failed to read default cache\n"));
 495                 goto out;
 496         }
 497         if (krb5_cc_get_principal(ctx, cc, &princ)) {
 498                 DEBUG(0,("kerberos_get_default_realm_from_ccache: "
 499                         "failed to get default principal\n"));
 500                 goto out;
 501         }
 502 
 503 #if defined(HAVE_KRB5_PRINCIPAL_GET_REALM)
 504         realm = SMB_STRDUP(krb5_principal_get_realm(ctx, princ));
 505 #elif defined(HAVE_KRB5_PRINC_REALM)
 506         {
 507                 krb5_data *realm_data = krb5_princ_realm(ctx, princ);
 508                 realm = SMB_STRNDUP(realm_data->data, realm_data->length);
 509         }
 510 #endif
 511 
 512   out:
 513 
 514         if (ctx) {
 515                 if (princ) {
 516                         krb5_free_principal(ctx, princ);
 517                 }
 518                 if (cc) {
 519                         krb5_cc_close(ctx, cc);
 520                 }
 521                 krb5_free_context(ctx);
 522         }
 523 
 524         return realm;
 525 }
 526 
 527 
 528 /************************************************************************
 529  Routine to get the salting principal for this service.  This is 
 530  maintained for backwards compatibilty with releases prior to 3.0.24.
 531  Since we store the salting principal string only at join, we may have 
 532  to look for the older tdb keys.  Caller must free if return is not null.
 533  ************************************************************************/
 534 
 535 krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 536                                                         krb5_principal host_princ,
 537                                                         int enctype)
 538 {
 539         char *unparsed_name = NULL, *salt_princ_s = NULL;
 540         krb5_principal ret_princ = NULL;
 541         
 542         /* lookup new key first */
 543 
 544         if ( (salt_princ_s = kerberos_secrets_fetch_des_salt()) == NULL ) {
 545         
 546                 /* look under the old key.  If this fails, just use the standard key */
 547 
 548                 if (smb_krb5_unparse_name(talloc_tos(), context, host_princ, &unparsed_name) != 0) {
 549                         return (krb5_principal)NULL;
 550                 }
 551                 if ((salt_princ_s = kerberos_secrets_fetch_salting_principal(unparsed_name, enctype)) == NULL) {
 552                         /* fall back to host/machine.realm@REALM */
 553                         salt_princ_s = kerberos_standard_des_salt();
 554                 }
 555         }
 556 
 557         if (smb_krb5_parse_name(context, salt_princ_s, &ret_princ) != 0) {
 558                 ret_princ = NULL;
 559         }
 560         
 561         TALLOC_FREE(unparsed_name);
 562         SAFE_FREE(salt_princ_s);
 563         
 564         return ret_princ;
 565 }
 566 
 567 /************************************************************************
 568  Routine to set the salting principal for this service.  Active
 569  Directory may use a non-obvious principal name to generate the salt
 570  when it determines the key to use for encrypting tickets for a service,
 571  and hopefully we detected that when we joined the domain.
 572  Setting principal to NULL deletes this entry.
 573  ************************************************************************/
 574 
 575 bool kerberos_secrets_store_salting_principal(const char *service,
     /* [<][>][^][v][top][bottom][index][help] */
 576                                               int enctype,
 577                                               const char *principal)
 578 {
 579         char *key = NULL;
 580         bool ret = False;
 581         krb5_context context = NULL;
 582         krb5_principal princ = NULL;
 583         char *princ_s = NULL;
 584         char *unparsed_name = NULL;
 585         krb5_error_code code;
 586 
 587         if (((code = krb5_init_context(&context)) != 0) || (context == NULL)) {
 588                 DEBUG(5, ("kerberos_secrets_store_salting_pricipal: kdb5_init_context failed: %s\n",
 589                           error_message(code)));
 590                 return False;
 591         }
 592         if (strchr_m(service, '@')) {
 593                 if (asprintf(&princ_s, "%s", service) == -1) {
 594                         goto out;
 595                 }
 596         } else {
 597                 if (asprintf(&princ_s, "%s@%s", service, lp_realm()) == -1) {
 598                         goto out;
 599                 }
 600         }
 601 
 602         if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
 603                 goto out;
 604                 
 605         }
 606         if (smb_krb5_unparse_name(talloc_tos(), context, princ, &unparsed_name) != 0) {
 607                 goto out;
 608         }
 609 
 610         if (asprintf(&key, "%s/%s/enctype=%d",
 611                      SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype)
 612             == -1) {
 613                 goto out;
 614         }
 615 
 616         if ((principal != NULL) && (strlen(principal) > 0)) {
 617                 ret = secrets_store(key, principal, strlen(principal) + 1);
 618         } else {
 619                 ret = secrets_delete(key);
 620         }
 621 
 622  out:
 623 
 624         SAFE_FREE(key);
 625         SAFE_FREE(princ_s);
 626         TALLOC_FREE(unparsed_name);
 627 
 628         if (princ) {
 629                 krb5_free_principal(context, princ);
 630         }
 631 
 632         if (context) {
 633                 krb5_free_context(context);
 634         }
 635 
 636         return ret;
 637 }
 638 
 639 
 640 /************************************************************************
 641 ************************************************************************/
 642 
 643 int kerberos_kinit_password(const char *principal,
     /* [<][>][^][v][top][bottom][index][help] */
 644                             const char *password,
 645                             int time_offset,
 646                             const char *cache_name)
 647 {
 648         return kerberos_kinit_password_ext(principal, 
 649                                            password, 
 650                                            time_offset, 
 651                                            0, 
 652                                            0,
 653                                            cache_name,
 654                                            False,
 655                                            False,
 656                                            0,
 657                                            NULL);
 658 }
 659 
 660 /************************************************************************
 661 ************************************************************************/
 662 
 663 static char *print_kdc_line(char *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 664                         const char *prev_line,
 665                         const struct sockaddr_storage *pss)
 666 {
 667         char *kdc_str = NULL;
 668 
 669         if (pss->ss_family == AF_INET) {
 670                 kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
 671                                         prev_line,
 672                                         print_canonical_sockaddr(mem_ctx, pss));
 673         } else {
 674                 char addr[INET6_ADDRSTRLEN];
 675                 uint16_t port = get_sockaddr_port(pss);
 676 
 677                 if (port != 0 && port != DEFAULT_KRB5_PORT) {
 678                         /* Currently for IPv6 we can't specify a non-default
 679                            krb5 port with an address, as this requires a ':'.
 680                            Resolve to a name. */
 681                         char hostname[MAX_DNS_NAME_LENGTH];
 682                         int ret = sys_getnameinfo((const struct sockaddr *)pss,
 683                                         sizeof(*pss),
 684                                         hostname, sizeof(hostname),
 685                                         NULL, 0,
 686                                         NI_NAMEREQD);
 687                         if (ret) {
 688                                 DEBUG(0,("print_kdc_line: can't resolve name "
 689                                         "for kdc with non-default port %s. "
 690                                         "Error %s\n.",
 691                                         print_canonical_sockaddr(mem_ctx, pss),
 692                                         gai_strerror(ret)));
 693                         }
 694                         /* Success, use host:port */
 695                         kdc_str = talloc_asprintf(mem_ctx,
 696                                         "%s\tkdc = %s:%u\n",
 697                                         prev_line,
 698                                         hostname,
 699                                         (unsigned int)port);
 700                 } else {
 701                         kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
 702                                         prev_line,
 703                                         print_sockaddr(addr,
 704                                                 sizeof(addr),
 705                                                 pss));
 706                 }
 707         }
 708         return kdc_str;
 709 }
 710 
 711 /************************************************************************
 712  Create a string list of available kdc's, possibly searching by sitename.
 713  Does DNS queries.
 714 
 715  If "sitename" is given, the DC's in that site are listed first.
 716 
 717 ************************************************************************/
 718 
 719 static char *get_kdc_ip_string(char *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 720                 const char *realm,
 721                 const char *sitename,
 722                 struct sockaddr_storage *pss)
 723 {
 724         int i;
 725         struct ip_service *ip_srv_site = NULL;
 726         struct ip_service *ip_srv_nonsite = NULL;
 727         int count_site = 0;
 728         int count_nonsite;
 729         char *kdc_str = print_kdc_line(mem_ctx, "", pss);
 730 
 731         if (kdc_str == NULL) {
 732                 return NULL;
 733         }
 734 
 735         /*
 736          * First get the KDC's only in this site, the rest will be
 737          * appended later
 738          */
 739 
 740         if (sitename) {
 741 
 742                 get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
 743 
 744                 for (i = 0; i < count_site; i++) {
 745                         if (sockaddr_equal((struct sockaddr *)&ip_srv_site[i].ss,
 746                                                    (struct sockaddr *)pss)) {
 747                                 continue;
 748                         }
 749                         /* Append to the string - inefficient
 750                          * but not done often. */
 751                         kdc_str = print_kdc_line(mem_ctx,
 752                                                 kdc_str,
 753                                                 &ip_srv_site[i].ss);
 754                         if (!kdc_str) {
 755                                 SAFE_FREE(ip_srv_site);
 756                                 return NULL;
 757                         }
 758                 }
 759         }
 760 
 761         /* Get all KDC's. */
 762 
 763         get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
 764 
 765         for (i = 0; i < count_nonsite; i++) {
 766                 int j;
 767 
 768                 if (sockaddr_equal((struct sockaddr *)&ip_srv_nonsite[i].ss, (struct sockaddr *)pss)) {
 769                         continue;
 770                 }
 771 
 772                 /* Ensure this isn't an IP already seen (YUK! this is n*n....) */
 773                 for (j = 0; j < count_site; j++) {
 774                         if (sockaddr_equal((struct sockaddr *)&ip_srv_nonsite[i].ss,
 775                                                 (struct sockaddr *)&ip_srv_site[j].ss)) {
 776                                 break;
 777                         }
 778                         /* As the lists are sorted we can break early if nonsite > site. */
 779                         if (ip_service_compare(&ip_srv_nonsite[i], &ip_srv_site[j]) > 0) {
 780                                 break;
 781                         }
 782                 }
 783                 if (j != i) {
 784                         continue;
 785                 }
 786 
 787                 /* Append to the string - inefficient but not done often. */
 788                 kdc_str = print_kdc_line(mem_ctx,
 789                                 kdc_str,
 790                                 &ip_srv_nonsite[i].ss);
 791                 if (!kdc_str) {
 792                         SAFE_FREE(ip_srv_site);
 793                         SAFE_FREE(ip_srv_nonsite);
 794                         return NULL;
 795                 }
 796         }
 797 
 798 
 799         SAFE_FREE(ip_srv_site);
 800         SAFE_FREE(ip_srv_nonsite);
 801 
 802         DEBUG(10,("get_kdc_ip_string: Returning %s\n",
 803                 kdc_str ));
 804 
 805         return kdc_str;
 806 }
 807 
 808 /************************************************************************
 809  Create  a specific krb5.conf file in the private directory pointing
 810  at a specific kdc for a realm. Keyed off domain name. Sets
 811  KRB5_CONFIG environment variable to point to this file. Must be
 812  run as root or will fail (which is a good thing :-).
 813 ************************************************************************/
 814 
 815 bool create_local_private_krb5_conf_for_domain(const char *realm,
     /* [<][>][^][v][top][bottom][index][help] */
 816                                                 const char *domain,
 817                                                 const char *sitename,
 818                                                 struct sockaddr_storage *pss)
 819 {
 820         char *dname = lock_path("smb_krb5");
 821         char *tmpname = NULL;
 822         char *fname = NULL;
 823         char *file_contents = NULL;
 824         char *kdc_ip_string = NULL;
 825         size_t flen = 0;
 826         ssize_t ret;
 827         int fd;
 828         char *realm_upper = NULL;
 829         bool result = false;
 830 
 831         if (!dname) {
 832                 return false;
 833         }
 834         if ((mkdir(dname, 0755)==-1) && (errno != EEXIST)) {
 835                 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
 836                         "failed to create directory %s. Error was %s\n",
 837                         dname, strerror(errno) ));
 838                 goto done;
 839         }
 840 
 841         tmpname = lock_path("smb_tmp_krb5.XXXXXX");
 842         if (!tmpname) {
 843                 goto done;
 844         }
 845 
 846         fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
 847         if (!fname) {
 848                 goto done;
 849         }
 850 
 851         DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
 852                 fname, realm, domain ));
 853 
 854         realm_upper = talloc_strdup(fname, realm);
 855         strupper_m(realm_upper);
 856 
 857         kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, pss);
 858         if (!kdc_ip_string) {
 859                 goto done;
 860         }
 861 
 862         file_contents = talloc_asprintf(fname,
 863                                         "[libdefaults]\n\tdefault_realm = %s\n"
 864                                         "\tdefault_tgs_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
 865                                         "\tdefault_tkt_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
 866                                         "\tpreferred_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n\n"
 867                                         "[realms]\n\t%s = {\n"
 868                                         "\t%s\t}\n",
 869                                         realm_upper, realm_upper, kdc_ip_string);
 870 
 871         if (!file_contents) {
 872                 goto done;
 873         }
 874 
 875         flen = strlen(file_contents);
 876 
 877         fd = smb_mkstemp(tmpname);
 878         if (fd == -1) {
 879                 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
 880                         " for file %s. Errno %s\n",
 881                         tmpname, strerror(errno) ));
 882                 goto done;
 883         }
 884 
 885         if (fchmod(fd, 0644)==-1) {
 886                 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
 887                         " Errno %s\n",
 888                         tmpname, strerror(errno) ));
 889                 unlink(tmpname);
 890                 close(fd);
 891                 goto done;
 892         }
 893 
 894         ret = write(fd, file_contents, flen);
 895         if (flen != ret) {
 896                 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
 897                         " returned %d (should be %u). Errno %s\n",
 898                         (int)ret, (unsigned int)flen, strerror(errno) ));
 899                 unlink(tmpname);
 900                 close(fd);
 901                 goto done;
 902         }
 903         if (close(fd)==-1) {
 904                 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
 905                         " Errno %s\n", strerror(errno) ));
 906                 unlink(tmpname);
 907                 goto done;
 908         }
 909 
 910         if (rename(tmpname, fname) == -1) {
 911                 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
 912                         "of %s to %s failed. Errno %s\n",
 913                         tmpname, fname, strerror(errno) ));
 914                 unlink(tmpname);
 915                 goto done;
 916         }
 917 
 918         DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
 919                 "file %s with realm %s KDC list = %s\n",
 920                 fname, realm_upper, kdc_ip_string));
 921 
 922         /* Set the environment variable to this file. */
 923         setenv("KRB5_CONFIG", fname, 1);
 924 
 925         result = true;
 926 
 927 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
 928 
 929 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
 930         /* Insanity, sheer insanity..... */
 931 
 932         if (strequal(realm, lp_realm())) {
 933                 char linkpath[PATH_MAX+1];
 934                 int lret;
 935 
 936                 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath, sizeof(linkpath)-1);
 937                 if (lret != -1) {
 938                         linkpath[lret] = '\0';
 939                 }
 940 
 941                 if (lret != -1 || strcmp(linkpath, fname) == 0) {
 942                         /* Symlink already exists. */
 943                         goto done;
 944                 }
 945 
 946                 /* Try and replace with a symlink. */
 947                 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
 948                         const char *newpath = SYSTEM_KRB5_CONF_PATH ## ".saved";
 949                         if (errno != EEXIST) {
 950                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
 951                                         "of %s to %s failed. Errno %s\n",
 952                                         fname, SYSTEM_KRB5_CONF_PATH, strerror(errno) ));
 953                                 goto done; /* Not a fatal error. */
 954                         }
 955 
 956                         /* Yes, this is a race conditon... too bad. */
 957                         if (rename(SYSTEM_KRB5_CONF_PATH, newpath) == -1) {
 958                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
 959                                         "of %s to %s failed. Errno %s\n",
 960                                         SYSTEM_KRB5_CONF_PATH, newpath,
 961                                         strerror(errno) ));
 962                                 goto done; /* Not a fatal error. */
 963                         }
 964 
 965                         if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
 966                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
 967                                         "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
 968                                         fname, strerror(errno) ));
 969                                 goto done; /* Not a fatal error. */
 970                         }
 971                 }
 972         }
 973 #endif
 974 
 975 done:
 976         TALLOC_FREE(tmpname);
 977         TALLOC_FREE(dname);
 978 
 979         return result;
 980 }
 981 #endif

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