context.c
1 /* 2 * Copyright (c) 1997 - 2010 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Portions Copyright (c) 2009 Apple Inc. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include "krb5_locl.h" 37 #include <assert.h> 38 #include <com_err.h> 39 40 #define INIT_FIELD(C, T, E, D, F) \ 41 (C)->E = krb5_config_get_ ## T ## _default ((C), NULL, (D), \ 42 "libdefaults", F, NULL) 43 44 #define INIT_FLAG(C, O, V, D, F) \ 45 do { \ 46 if (krb5_config_get_bool_default((C), NULL, (D),"libdefaults", F, NULL)) { \ 47 (C)->O |= V; \ 48 } \ 49 } while(0) 50 51 /* 52 * Variables 53 */ 54 55 static HEIMDAL_MUTEX homedir_mutex = HEIMDAL_MUTEX_INITIALIZER; 56 static krb5_boolean allow_homedir = TRUE; 57 58 /* 59 * Set the list of etypes `ret_etypes' from the configuration variable 60 * `name' 61 */ 62 63 static krb5_error_code 64 set_etypes (krb5_context context, 65 const char *name, 66 krb5_enctype **ret_enctypes) 67 { 68 char **etypes_str; 69 krb5_enctype *etypes = NULL; 70 71 etypes_str = krb5_config_get_strings(context, NULL, "libdefaults", 72 name, NULL); 73 if (etypes_str){ 74 int i, j, k; 75 for (i = 0; etypes_str[i]; i++); 76 etypes = malloc((i+1) * sizeof(*etypes)); 77 if (etypes == NULL) { 78 krb5_config_free_strings (etypes_str); 79 krb5_set_error_message (context, ENOMEM, N_("malloc: out of memory", "")); 80 return ENOMEM; 81 } 82 for(j = 0, k = 0; j < i; j++) { 83 krb5_enctype e; 84 if (krb5_string_to_enctype(context, etypes_str[j], &e) != 0) 85 continue; 86 if (krb5_enctype_valid(context, e) != 0) 87 continue; 88 etypes[k++] = e; 89 } 90 etypes[k] = ETYPE_NULL; 91 krb5_config_free_strings(etypes_str); 92 } 93 *ret_enctypes = etypes; 94 return 0; 95 } 96 97 #ifdef __APPLE__ 98 99 static CFTypeRef 100 CopyKeyFromFile(CFStringRef file, CFStringRef key) 101 { 102 CFReadStreamRef s; 103 CFDictionaryRef d; 104 CFErrorRef e; 105 CFURLRef url; 106 CFTypeRef val; 107 108 url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, file, kCFURLPOSIXPathStyle, false); 109 if (url == NULL) 110 return NULL; 111 112 s = CFReadStreamCreateWithFile(kCFAllocatorDefault, url); 113 CFRelease(url); 114 if (s == NULL) 115 return NULL; 116 117 if (!CFReadStreamOpen(s)) { 118 CFRelease(s); 119 return NULL; 120 } 121 122 d = (CFDictionaryRef)CFPropertyListCreateWithStream (kCFAllocatorDefault, s, 0, kCFPropertyListImmutable, NULL, &e); 123 CFRelease(s); 124 if (d == NULL) 125 return NULL; 126 127 if (CFGetTypeID(d) != CFDictionaryGetTypeID()) { 128 CFRelease(d); 129 return NULL; 130 } 131 132 val = CFDictionaryGetValue(d, key); 133 if (val) 134 CFRetain(val); 135 CFRelease(d); 136 return val; 137 } 138 139 #endif /* __APPLE__ */ 140 141 /* 142 * read variables from the configuration file and set in `context' 143 */ 144 145 static krb5_error_code 146 init_context_from_config_file(krb5_context context) 147 { 148 krb5_error_code ret; 149 const char * tmp; 150 char **s; 151 krb5_enctype *tmptypes; 152 153 INIT_FIELD(context, time, max_skew, 5 * 60, "clockskew"); 154 INIT_FIELD(context, time, kdc_timeout, 30, "kdc_timeout"); 155 INIT_FIELD(context, time, host_timeout, 3, "host_timeout"); 156 INIT_FIELD(context, time, tgs_negative_timeout, 1200, "tgs_negative_cache_timeout"); 157 INIT_FIELD(context, int, max_retries, 3, "max_retries"); 158 159 INIT_FIELD(context, string, http_proxy, NULL, "http_proxy"); 160 161 ret = krb5_config_get_bool_default(context, NULL, FALSE, 162 "libdefaults", 163 "allow_weak_crypto", NULL); 164 if (ret) { 165 krb5_allow_weak_crypto(context, TRUE); 166 } 167 168 ret = set_etypes (context, "default_etypes", &tmptypes); 169 if (ret) 170 return ret; 171 free(context->etypes); 172 context->etypes = tmptypes; 173 174 ret = set_etypes (context, "default_etypes_des", &tmptypes); 175 if (ret) 176 return ret; 177 free(context->etypes_des); 178 context->etypes_des = tmptypes; 179 180 ret = set_etypes (context, "default_as_etypes", &tmptypes); 181 if(ret) 182 return ret; 183 free(context->as_etypes); 184 context->as_etypes = tmptypes; 185 186 ret = set_etypes (context, "default_tgs_etypes", &tmptypes); 187 if(ret) 188 return ret; 189 free(context->tgs_etypes); 190 context->tgs_etypes = tmptypes; 191 192 ret = set_etypes (context, "permitted_enctypes", &tmptypes); 193 if(ret) 194 return ret; 195 free(context->permitted_enctypes); 196 context->permitted_enctypes = tmptypes; 197 198 /* default keytab name */ 199 tmp = NULL; 200 if (!issuid()) 201 tmp = getenv("KRB5_KTNAME"); 202 if (tmp != NULL) 203 context->default_keytab = tmp; 204 else 205 INIT_FIELD(context, string, default_keytab, 206 KEYTAB_DEFAULT, "default_keytab_name"); 207 208 INIT_FIELD(context, string, default_keytab_modify, 209 NULL, "default_keytab_modify_name"); 210 211 INIT_FIELD(context, string, time_fmt, 212 "%Y-%m-%dT%H:%M:%S", "time_format"); 213 214 INIT_FIELD(context, string, date_fmt, 215 "%Y-%m-%d", "date_format"); 216 217 INIT_FIELD(context, bool, log_utc, 218 FALSE, "log_utc"); 219 220 221 222 /* init dns-proxy slime */ 223 tmp = krb5_config_get_string(context, NULL, "libdefaults", 224 "dns_proxy", NULL); 225 if (tmp) 226 roken_gethostby_setup(context->http_proxy, tmp); 227 228 heim_release(context->default_realms); 229 context->default_realms = NULL; 230 231 { 232 krb5_addresses addresses; 233 char **adr, **a; 234 235 krb5_set_extra_addresses(context, NULL); 236 adr = krb5_config_get_strings(context, NULL, 237 "libdefaults", 238 "extra_addresses", 239 NULL); 240 memset(&addresses, 0, sizeof(addresses)); 241 for(a = adr; a && *a; a++) { 242 ret = krb5_parse_address(context, *a, &addresses); 243 if (ret == 0) { 244 krb5_add_extra_addresses(context, &addresses); 245 krb5_free_addresses(context, &addresses); 246 } 247 } 248 krb5_config_free_strings(adr); 249 250 krb5_set_ignore_addresses(context, NULL); 251 adr = krb5_config_get_strings(context, NULL, 252 "libdefaults", 253 "ignore_addresses", 254 NULL); 255 memset(&addresses, 0, sizeof(addresses)); 256 for(a = adr; a && *a; a++) { 257 ret = krb5_parse_address(context, *a, &addresses); 258 if (ret == 0) { 259 krb5_add_ignore_addresses(context, &addresses); 260 krb5_free_addresses(context, &addresses); 261 } 262 } 263 krb5_config_free_strings(adr); 264 } 265 266 INIT_FIELD(context, bool, scan_interfaces, TRUE, "scan_interfaces"); 267 INIT_FIELD(context, int, fcache_vno, 0, "fcache_version"); 268 /* prefer dns_lookup_kdc over srv_lookup. */ 269 INIT_FIELD(context, bool, srv_lookup, TRUE, "srv_lookup"); 270 INIT_FIELD(context, bool, srv_lookup, context->srv_lookup, "dns_lookup_kdc"); 271 INIT_FIELD(context, int, large_msg_size, 1400, "large_message_size"); 272 INIT_FIELD(context, int, max_msg_size, 1000 * 1024, "maximum_message_size"); 273 INIT_FIELD(context, int, max_srv_entries, 5, "max_srv_entries"); 274 INIT_FLAG(context, flags, KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME, TRUE, "dns_canonicalize_hostname"); 275 INIT_FLAG(context, flags, KRB5_CTX_F_CHECK_PAC, TRUE, "check_pac"); 276 277 if (context->default_cc_name) 278 free(context->default_cc_name); 279 context->default_cc_name = NULL; 280 context->default_cc_name_set = 0; 281 282 s = krb5_config_get_strings(context, NULL, "logging", "krb5", NULL); 283 if (s) { 284 char **p; 285 286 if (context->debug_dest) 287 krb5_closelog(context, context->debug_dest); 288 289 krb5_initlog(context, "libkrb5", &context->debug_dest); 290 for(p = s; *p; p++) 291 krb5_addlog_dest(context, context->debug_dest, *p); 292 krb5_config_free_strings(s); 293 } else if (context->debug_dest == NULL) { 294 char *logline = NULL; 295 296 if (!issuid()) { 297 char *e = getenv("KRB5_TRACE"); 298 if (e) 299 asprintf(&logline, "0-/FILE:%s", e); 300 } 301 302 #if __APPLE__ 303 304 #ifdef __APPLE_TARGET_EMBEDDED__ 305 #define GLOBAL_PREFERENCE_FILE CFSTR("/Library/Managed Preferences/mobile/.GlobalPreferences.plist") 306 #else 307 #define GLOBAL_PREFERENCE_FILE CFSTR("/Library/Managed Preferences/.GlobalPreferences.plist") 308 #endif 309 310 if (logline == NULL) { 311 CFTypeRef val = NULL; 312 313 if (geteuid() && krb5_homedir_access(NULL)) { 314 /* 315 * Pick up global preferences that can be configured via a 316 * profile. 317 */ 318 val = CFPreferencesCopyAppValue(CFSTR("KerberosDebugLevel"), CFSTR(".GlobalPreferences")); 319 } else { 320 val = CopyKeyFromFile(GLOBAL_PREFERENCE_FILE, CFSTR("KerberosDebugLevel")); 321 } 322 if (val) { 323 int logLevel = 1; 324 325 if (CFGetTypeID(val) == CFBooleanGetTypeID()) 326 logLevel = CFBooleanGetValue(val) ? 1 : 0; 327 else if (CFGetTypeID(val) == CFNumberGetTypeID()) 328 CFNumberGetValue(val, kCFNumberIntType, &logLevel); 329 else 330 /* ignore other types */; 331 CFRelease(val); 332 333 asprintf(&logline, "0-%d/OSLOG:normal:libkrb5", logLevel); 334 } 335 } 336 #endif /* __APPLE__ */ 337 338 krb5_initlog(context, "libkrb5", &context->debug_dest); 339 if (logline) { 340 krb5_addlog_dest(context, context->debug_dest, logline); 341 free(logline); 342 } else { 343 krb5_addlog_dest(context, context->debug_dest, "0-10/OSLOG:normal:libkrb5"); 344 } 345 } 346 347 tmp = krb5_config_get_string(context, NULL, "libdefaults", 348 "check-rd-req-server", NULL); 349 if (tmp == NULL && !issuid()) 350 tmp = getenv("KRB5_CHECK_RD_REQ_SERVER"); 351 if(tmp) { 352 if (strcasecmp(tmp, "ignore") == 0) 353 context->flags |= KRB5_CTX_F_RD_REQ_IGNORE; 354 } 355 356 return 0; 357 } 358 359 static krb5_error_code 360 cc_ops_register(krb5_context context) 361 { 362 context->cc_ops = NULL; 363 context->num_cc_ops = 0; 364 365 #if HAVE_ACC 366 krb5_cc_register(context, &krb5_acc_ops, TRUE); 367 #endif 368 krb5_cc_register(context, &krb5_fcc_ops, TRUE); 369 krb5_cc_register(context, &krb5_mcc_ops, TRUE); 370 #ifdef HAVE_SCC 371 krb5_cc_register(context, &krb5_scc_ops, TRUE); 372 #endif 373 #ifdef HAVE_KCM 374 #ifdef KCM_IS_API_CACHE 375 krb5_cc_register(context, &krb5_akcm_ops, TRUE); 376 #endif 377 krb5_cc_register(context, &krb5_kcm_ops, TRUE); 378 #endif 379 #ifdef HAVE_XCC 380 #ifdef XCACHE_IS_API_CACHE 381 krb5_cc_register(context, &krb5_xcc_api_ops, TRUE); 382 #endif 383 krb5_cc_register(context, &krb5_xcc_ops, TRUE); 384 krb5_cc_register(context, &krb5_xcc_temp_api_ops, TRUE); 385 #endif 386 _krb5_load_ccache_plugins(context); 387 return 0; 388 } 389 390 static krb5_error_code 391 kt_ops_register(krb5_context context) 392 { 393 context->num_kt_types = 0; 394 context->kt_types = NULL; 395 396 krb5_kt_register (context, &krb5_fkt_ops); 397 krb5_kt_register (context, &krb5_wrfkt_ops); 398 krb5_kt_register (context, &krb5_javakt_ops); 399 #ifdef HEIM_KT_MEMORY 400 krb5_kt_register (context, &krb5_mkt_ops); 401 #endif 402 #ifdef HEIM_KT_AKF 403 krb5_kt_register (context, &krb5_akf_ops); 404 #endif 405 #ifdef HEIM_KT_ANY 406 krb5_kt_register (context, &krb5_any_ops); 407 #endif 408 return 0; 409 } 410 411 #ifdef HAVE_NOTIFY_H 412 static int check_token = -1; 413 static int config_token = -1; 414 #endif 415 416 static const char *sysplugin_dirs[] = { 417 LIBDIR "/plugin/krb5", 418 #ifdef __APPLE__ 419 "/Library/KerberosPlugins/KerberosFrameworkPlugins", 420 "/System/Library/KerberosPlugins/KerberosFrameworkPlugins", 421 #endif 422 NULL 423 }; 424 425 static void 426 init_context_once(void *ctx) 427 { 428 krb5_context context = ctx; 429 430 #ifdef HAVE_NOTIFY_H 431 notify_register_check(KRB5_CONFIGURATION_CHANGE_NOTIFY_NAME, 432 &check_token); 433 notify_register_check("com.apple.ManagedConfiguration.profileListChanged", 434 &config_token); 435 #endif 436 437 krb5_load_plugins(context, "krb5", sysplugin_dirs); 438 439 bindtextdomain(HEIMDAL_TEXTDOMAIN, HEIMDAL_LOCALEDIR); 440 } 441 442 static void 443 context_release(void *ptr) 444 { 445 krb5_context context = (krb5_context)ptr; 446 447 if (context->default_cc_name) 448 free(context->default_cc_name); 449 if (context->default_cc_name_env) 450 free(context->default_cc_name_env); 451 if (context->config_files) 452 krb5_free_config_files(context->config_files); 453 free(context->etypes); 454 free(context->etypes_des); 455 heim_release(context->default_realms); 456 krb5_config_file_free (context, context->cf); 457 free_error_table (context->et_list); 458 free(rk_UNCONST(context->cc_ops)); 459 free(context->kt_types); 460 krb5_clear_error_message(context); 461 if (context->warn_dest != NULL) 462 krb5_closelog(context, context->warn_dest); 463 if (context->debug_dest != NULL) 464 krb5_closelog(context, context->debug_dest); 465 krb5_set_extra_addresses(context, NULL); 466 krb5_set_ignore_addresses(context, NULL); 467 #ifndef HEIMDAL_SMALLER 468 krb5_set_send_to_kdc_func(context, NULL, NULL); 469 #endif 470 471 #ifdef PKINIT 472 if (context->hx509ctx) 473 hx509_context_free(&context->hx509ctx); 474 #endif 475 476 HEIMDAL_MUTEX_destroy(context->mutex); 477 free(context->mutex); 478 if (context->flags & KRB5_CTX_F_SOCKETS_INITIALIZED) { 479 rk_SOCK_EXIT(); 480 } 481 } 482 483 /** 484 * Initializes the context structure and reads the configuration files. 485 * 486 * The structure should be freed by calling 487 * krb5_free_context() when it is no longer being used. 488 * 489 * @param context pointer to returned context 490 * @param flags controls context creation failure. 491 * 492 * Possible flags are: 493 * - KRB5_CONTEXT_FLAG_NO_CONFIG - don't read the any configuration files 494 * 495 * @return Returns 0 to indicate success. Otherwise an errno code is 496 * returned. Failure means either that something bad happened during 497 * initialization (typically ENOMEM) or that Kerberos should not be 498 * used ENXIO. 499 * 500 * @see krb5_init_context 501 * @ingroup krb5 502 */ 503 504 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 505 krb5_init_context_flags(unsigned int flags, krb5_context *context) 506 { 507 static heim_base_once_t init_context = HEIM_BASE_ONCE_INIT; 508 krb5_context p; 509 krb5_error_code ret; 510 char **files = NULL; 511 512 *context = NULL; 513 514 p = heim_uniq_alloc(sizeof(*p), "krb5-context", context_release); 515 if (!p) 516 return ENOMEM; 517 518 p->mutex = malloc(sizeof(HEIMDAL_MUTEX)); 519 if (p->mutex == NULL) { 520 heim_release(p); 521 return ENOMEM; 522 } 523 HEIMDAL_MUTEX_init(p->mutex); 524 525 HEIMDAL_MUTEX_lock(&homedir_mutex); 526 if (allow_homedir) 527 p->flags |= KRB5_CTX_F_HOMEDIR_ACCESS; 528 HEIMDAL_MUTEX_unlock(&homedir_mutex); 529 530 if ((flags & KRB5_CONTEXT_FLAG_NO_CONFIG) == 0) { 531 ret = krb5_get_default_config_files(&files); 532 if (ret) 533 goto out; 534 } 535 ret = krb5_set_config_files(p, files); 536 krb5_free_config_files(files); 537 if (ret) 538 goto out; 539 540 heim_base_once_f(&init_context, p, init_context_once); 541 542 /* init error tables */ 543 krb5_init_ets(p); 544 cc_ops_register(p); 545 kt_ops_register(p); 546 547 #ifdef PKINIT 548 ret = hx509_context_init(&p->hx509ctx); 549 if (ret) 550 goto out; 551 #endif 552 #if rk_SOCK_INIT 553 if (rk_SOCK_INIT()) 554 p->flags |= KRB5_CTX_F_SOCKETS_INITIALIZED; 555 #endif 556 557 out: 558 if (ret) { 559 krb5_free_context(p); 560 p = NULL; 561 } 562 563 *context = p; 564 return ret; 565 } 566 567 /** 568 * Initializes the context structure and reads the configuration files. 569 570 * The structure should be freed by calling krb5_free_context() when 571 * it is no longer being used. 572 * 573 * @param context pointer to returned context 574 * 575 * @return Returns 0 to indicate success. 576 * 577 * @ingroup krb5 578 */ 579 580 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 581 krb5_init_context(krb5_context *context) 582 { 583 return krb5_init_context_flags(0, context); 584 } 585 586 587 #ifndef HEIMDAL_SMALLER 588 589 static krb5_error_code 590 cc_ops_copy(krb5_context context, const krb5_context src_context) 591 { 592 const krb5_cc_ops **cc_ops; 593 594 context->cc_ops = NULL; 595 context->num_cc_ops = 0; 596 597 if (src_context->num_cc_ops == 0) 598 return 0; 599 600 cc_ops = malloc(sizeof(cc_ops[0]) * src_context->num_cc_ops); 601 if (cc_ops == NULL) { 602 krb5_set_error_message(context, KRB5_CC_NOMEM, 603 N_("malloc: out of memory", "")); 604 return KRB5_CC_NOMEM; 605 } 606 607 memcpy(cc_ops, src_context->cc_ops, 608 sizeof(cc_ops[0]) * src_context->num_cc_ops); 609 context->cc_ops = cc_ops; 610 context->num_cc_ops = src_context->num_cc_ops; 611 612 return 0; 613 } 614 615 static krb5_error_code 616 kt_ops_copy(krb5_context context, const krb5_context src_context) 617 { 618 context->num_kt_types = 0; 619 context->kt_types = NULL; 620 621 if (src_context->num_kt_types == 0) 622 return 0; 623 624 context->kt_types = malloc(sizeof(context->kt_types[0]) * src_context->num_kt_types); 625 if (context->kt_types == NULL) { 626 krb5_set_error_message(context, ENOMEM, 627 N_("malloc: out of memory", "")); 628 return ENOMEM; 629 } 630 631 context->num_kt_types = src_context->num_kt_types; 632 memcpy(context->kt_types, src_context->kt_types, 633 sizeof(context->kt_types[0]) * src_context->num_kt_types); 634 635 return 0; 636 } 637 638 /* 639 * 640 */ 641 642 static krb5_error_code 643 copy_etypes (krb5_context context, 644 krb5_enctype *enctypes, 645 krb5_enctype **ret_enctypes) 646 { 647 unsigned int i; 648 649 for (i = 0; enctypes[i]; i++) 650 ; 651 i++; 652 653 *ret_enctypes = malloc(sizeof(ret_enctypes[0]) * i); 654 if (*ret_enctypes == NULL) { 655 krb5_set_error_message(context, ENOMEM, 656 N_("malloc: out of memory", "")); 657 return ENOMEM; 658 } 659 memcpy(*ret_enctypes, enctypes, sizeof(ret_enctypes[0]) * i); 660 return 0; 661 } 662 663 /** 664 * Make a copy for the Kerberos 5 context, the new krb5_context shoud 665 * be freed with krb5_free_context(). 666 * 667 * @param context the Kerberos context to copy 668 * @param out the copy of the Kerberos, set to NULL error. 669 * 670 * @return Returns 0 to indicate success. Otherwise an kerberos et 671 * error code is returned, see krb5_get_error_message(). 672 * 673 * @ingroup krb5 674 */ 675 676 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 677 krb5_copy_context(krb5_context context, krb5_context *out) 678 { 679 krb5_error_code ret; 680 krb5_context p; 681 682 *out = NULL; 683 684 p = calloc(1, sizeof(*p)); 685 if (p == NULL) { 686 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 687 return ENOMEM; 688 } 689 690 p->mutex = malloc(sizeof(HEIMDAL_MUTEX)); 691 if (p->mutex == NULL) { 692 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 693 free(p); 694 return ENOMEM; 695 } 696 HEIMDAL_MUTEX_init(p->mutex); 697 698 699 if (context->default_cc_name) 700 p->default_cc_name = strdup(context->default_cc_name); 701 if (context->default_cc_name_env) 702 p->default_cc_name_env = strdup(context->default_cc_name_env); 703 704 if (context->etypes) { 705 ret = copy_etypes(context, context->etypes, &p->etypes); 706 if (ret) 707 goto out; 708 } 709 if (context->etypes_des) { 710 ret = copy_etypes(context, context->etypes_des, &p->etypes_des); 711 if (ret) 712 goto out; 713 } 714 715 if (context->default_realms) 716 p->default_realms = heim_retain(context->default_realms); 717 718 ret = _krb5_config_copy(context, context->cf, &p->cf); 719 if (ret) 720 goto out; 721 722 /* XXX should copy */ 723 krb5_init_ets(p); 724 725 cc_ops_copy(p, context); 726 kt_ops_copy(p, context); 727 728 #if 0 /* XXX */ 729 if (context->warn_dest != NULL) 730 ; 731 if (context->debug_dest != NULL) 732 ; 733 #endif 734 735 ret = krb5_set_extra_addresses(p, context->extra_addresses); 736 if (ret) 737 goto out; 738 ret = krb5_set_extra_addresses(p, context->ignore_addresses); 739 if (ret) 740 goto out; 741 742 ret = _krb5_copy_send_to_kdc_func(p, context); 743 if (ret) 744 goto out; 745 746 *out = p; 747 748 return 0; 749 750 out: 751 krb5_free_context(p); 752 return ret; 753 } 754 755 #endif 756 757 /** 758 * Frees the krb5_context allocated by krb5_init_context(). 759 * 760 * @param context context to be freed. 761 * 762 * @ingroup krb5 763 */ 764 765 KRB5_LIB_FUNCTION void KRB5_LIB_CALL 766 krb5_free_context(krb5_context context) 767 { 768 heim_release(context); 769 } 770 771 static krb5_error_code 772 add_file(char ***pfilenames, unsigned *len, char *file) 773 { 774 char **pp = *pfilenames; 775 unsigned i; 776 777 for (i = 0; i < *len; i++) 778 if (strcmp(pp[i], file) == 0) 779 return 0; 780 781 pp = realloc(*pfilenames, (*len + 2) * sizeof(*pp)); 782 if (pp == NULL) 783 return ENOMEM; 784 *pfilenames = pp; 785 786 pp[*len] = strdup(file); 787 if (pp[*len] == NULL) 788 return ENOMEM; 789 pp[*len + 1] = NULL; 790 *len += 1; 791 return 0; 792 } 793 794 /** 795 * Reinit the context from a new set of filenames. 796 * 797 * @param context context to add configuration too. 798 * @param filenames array of filenames, end of list is indicated with a NULL filename. 799 * 800 * @return Returns 0 to indicate success. Otherwise an kerberos et 801 * error code is returned, see krb5_get_error_message(). 802 * 803 * @ingroup krb5 804 */ 805 806 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 807 krb5_set_config_files(krb5_context context, char **filenames) 808 { 809 krb5_error_code ret; 810 krb5_config_binding *tmp = NULL; 811 char **files = NULL; 812 813 if (filenames) { 814 unsigned len = 0; 815 816 while (*filenames != NULL && **filenames != '\0') { 817 818 ret = add_file(&files, &len, *filenames); 819 if (ret == 0) 820 ret = krb5_config_parse_file_multi(context, *filenames, &tmp); 821 822 if (ret != 0 && ret != ENOENT && ret != EACCES && ret != EPERM && ret != KRB5_CONFIG_BADFORMAT) { 823 krb5_free_config_files(files); 824 krb5_config_file_free(context, tmp); 825 return ret; 826 } 827 filenames++; 828 } 829 } 830 831 krb5_free_config_files(context->config_files); 832 context->config_files = files; 833 834 #if 0 835 /* with this enabled and if there are no config files, Kerberos is 836 considererd disabled */ 837 if (tmp == NULL) 838 return ENXIO; 839 #endif 840 841 #ifdef _WIN32 842 _krb5_load_config_from_registry(context, &tmp); 843 #endif 844 845 krb5_config_file_free(context, context->cf); 846 context->cf = tmp; 847 ret = init_context_from_config_file(context); 848 return ret; 849 } 850 851 /* 852 * `pq' isn't free, it's up the the caller 853 */ 854 855 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 856 krb5_prepend_config_files(const char *filelist, char **pq, char ***ret_pp) 857 { 858 krb5_error_code ret; 859 const char *q, *p = filelist; 860 char **pp = NULL; 861 unsigned len = 0; 862 char *fn; 863 864 while(1) { 865 ssize_t l; 866 q = p; 867 l = strsep_copy(&q, PATH_SEP, NULL, 0); 868 if(l == -1) 869 break; 870 fn = malloc(l + 1); 871 if (fn == NULL) { 872 krb5_free_config_files(pp); 873 return ENOMEM; 874 } 875 (void)strsep_copy(&p, PATH_SEP, fn, l + 1); 876 ret = add_file(&pp, &len, fn); 877 free(fn); 878 if (ret) { 879 krb5_free_config_files(pp); 880 return ret; 881 } 882 } 883 884 if (pq != NULL) { 885 int i; 886 887 for (i = 0; pq[i] != NULL; i++) { 888 ret = add_file(&pp, &len, pq[i]); 889 if (ret) { 890 krb5_free_config_files(pp); 891 return ret; 892 } 893 } 894 } 895 896 *ret_pp = pp; 897 return 0; 898 } 899 900 /** 901 * Prepend the filename to the global configuration list. 902 * 903 * @param filelist a filename to add to the default list of filename 904 * @param pfilenames return array of filenames, should be freed with krb5_free_config_files(). 905 * 906 * @return Returns 0 to indicate success. Otherwise an kerberos et 907 * error code is returned, see krb5_get_error_message(). 908 * 909 * @ingroup krb5 910 */ 911 912 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 913 krb5_prepend_config_files_default(const char *filelist, char ***pfilenames) 914 { 915 krb5_error_code ret; 916 char **defpp, **pp = NULL; 917 918 ret = krb5_get_default_config_files(&defpp); 919 if (ret) 920 return ret; 921 922 ret = krb5_prepend_config_files(filelist, defpp, &pp); 923 krb5_free_config_files(defpp); 924 if (ret) { 925 return ret; 926 } 927 *pfilenames = pp; 928 return 0; 929 } 930 931 #ifdef _WIN32 932 933 /** 934 * Checks the registry for configuration file location 935 * 936 * Kerberos for Windows and other legacy Kerberos applications expect 937 * to find the configuration file location in the 938 * SOFTWARE\MIT\Kerberos registry key under the value "config". 939 */ 940 char * 941 _krb5_get_default_config_config_files_from_registry() 942 { 943 static const char * KeyName = "Software\\MIT\\Kerberos"; 944 char *config_file = NULL; 945 LONG rcode; 946 HKEY key; 947 948 rcode = RegOpenKeyEx(HKEY_CURRENT_USER, KeyName, 0, KEY_READ, &key); 949 if (rcode == ERROR_SUCCESS) { 950 config_file = _krb5_parse_reg_value_as_multi_string(NULL, key, "config", 951 REG_NONE, 0, PATH_SEP); 952 RegCloseKey(key); 953 } 954 955 if (config_file) 956 return config_file; 957 958 rcode = RegOpenKeyEx(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &key); 959 if (rcode == ERROR_SUCCESS) { 960 config_file = _krb5_parse_reg_value_as_multi_string(NULL, key, "config", 961 REG_NONE, 0, PATH_SEP); 962 RegCloseKey(key); 963 } 964 965 return config_file; 966 } 967 968 #endif 969 970 /** 971 * Get the global configuration list. 972 * 973 * @param pfilenames return array of filenames, should be freed with krb5_free_config_files(). 974 * 975 * @return Returns 0 to indicate success. Otherwise an kerberos et 976 * error code is returned, see krb5_get_error_message(). 977 * 978 * @ingroup krb5 979 */ 980 981 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 982 krb5_get_default_config_files(char ***pfilenames) 983 { 984 const char *files = NULL; 985 986 if (pfilenames == NULL) 987 return EINVAL; 988 if (!issuid()) 989 files = getenv("KRB5_CONFIG"); 990 991 #ifdef _WIN32 992 if (files == NULL) { 993 char * reg_files; 994 reg_files = _krb5_get_default_config_config_files_from_registry(); 995 if (reg_files != NULL) { 996 krb5_error_code code; 997 998 code = krb5_prepend_config_files(reg_files, NULL, pfilenames); 999 free(reg_files); 1000 1001 return code; 1002 } 1003 } 1004 #endif 1005 1006 if (files == NULL) 1007 files = krb5_config_file; 1008 1009 return krb5_prepend_config_files(files, NULL, pfilenames); 1010 } 1011 1012 /** 1013 * Free a list of configuration files. 1014 * 1015 * @param filenames list, terminated with a NULL pointer, to be 1016 * freed. NULL is an valid argument. 1017 * 1018 * @ingroup krb5 1019 */ 1020 1021 KRB5_LIB_FUNCTION void KRB5_LIB_CALL 1022 krb5_free_config_files(char **filenames) 1023 { 1024 char **p; 1025 for(p = filenames; p && *p != NULL; p++) 1026 free(*p); 1027 free(filenames); 1028 } 1029 1030 /** 1031 * Returns the list of Kerberos encryption types sorted in order of 1032 * most preferred to least preferred encryption type. Note that some 1033 * encryption types might be disabled, so you need to check with 1034 * krb5_enctype_valid() before using the encryption type. 1035 * 1036 * @return list of enctypes, terminated with ETYPE_NULL. Its a static 1037 * array completed into the Kerberos library so the content doesn't 1038 * need to be freed. 1039 * 1040 * @ingroup krb5 1041 */ 1042 1043 KRB5_LIB_FUNCTION const krb5_enctype * KRB5_LIB_CALL 1044 krb5_kerberos_enctypes(krb5_context context) 1045 { 1046 static const krb5_enctype strong[] = { 1047 ETYPE_AES256_CTS_HMAC_SHA1_96, 1048 ETYPE_AES128_CTS_HMAC_SHA1_96, 1049 ETYPE_DES3_CBC_SHA1, 1050 ETYPE_NULL 1051 }; 1052 1053 static const krb5_enctype weak[] = { 1054 ETYPE_AES256_CTS_HMAC_SHA1_96, 1055 ETYPE_AES128_CTS_HMAC_SHA1_96, 1056 ETYPE_DES3_CBC_SHA1, 1057 ETYPE_ARCFOUR_HMAC_MD5, 1058 ETYPE_DES_CBC_MD5, 1059 ETYPE_DES_CBC_MD4, 1060 ETYPE_DES_CBC_CRC, 1061 ETYPE_NULL 1062 }; 1063 1064 /* 1065 * if the list of enctypes enabled by "allow_weak_crypto" 1066 * are valid, then return the former default enctype list 1067 * that contained the weak entries. 1068 */ 1069 size_t n; 1070 for (n = 0; weak[n] != ETYPE_NULL; n++) 1071 if (krb5_enctype_valid(context, weak[n]) != 0) 1072 return strong; 1073 1074 return weak; 1075 } 1076 1077 /* 1078 * 1079 */ 1080 1081 static krb5_error_code 1082 copy_enctypes(krb5_context context, 1083 const krb5_enctype *in, 1084 krb5_enctype **out) 1085 { 1086 krb5_enctype *p = NULL; 1087 size_t m, n; 1088 1089 for (n = 0; in[n]; n++) 1090 ; 1091 n++; 1092 ALLOC(p, n); 1093 if(p == NULL) 1094 return krb5_enomem(context); 1095 for (n = 0, m = 0; in[n]; n++) { 1096 if (krb5_enctype_valid(context, in[n]) != 0) 1097 continue; 1098 p[m++] = in[n]; 1099 } 1100 p[m] = KRB5_ENCTYPE_NULL; 1101 if (m == 0) { 1102 free(p); 1103 krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP, 1104 N_("no valid enctype set", "")); 1105 return KRB5_PROG_ETYPE_NOSUPP; 1106 } 1107 *out = p; 1108 return 0; 1109 } 1110 1111 1112 /* 1113 * set `etype' to a malloced list of the default enctypes 1114 */ 1115 1116 static krb5_error_code 1117 default_etypes(krb5_context context, krb5_enctype **etype) 1118 { 1119 static const krb5_enctype default_enctypes[] = { 1120 ETYPE_AES256_CTS_HMAC_SHA1_96, 1121 ETYPE_AES128_CTS_HMAC_SHA1_96, 1122 ETYPE_DES3_CBC_SHA1, 1123 ETYPE_ARCFOUR_HMAC_MD5, 1124 ETYPE_DES_CBC_MD5, 1125 ETYPE_DES_CBC_MD4, 1126 ETYPE_DES_CBC_CRC, 1127 ETYPE_NULL 1128 }; 1129 return copy_enctypes(context, default_enctypes, etype); 1130 } 1131 1132 /** 1133 * Set the default encryption types that will be use in communcation 1134 * with the KDC, clients and servers. 1135 * 1136 * If any of the enctypes selected are not valid, they are removed out 1137 * from the list. If the list becomes empty because non of the 1138 * proposed enctypes are supported, KRB5_PROG_ETYPE_NOSUPP is 1139 * returned. 1140 * 1141 * @param context Kerberos 5 context. 1142 * @param etypes Encryption types, array terminated with ETYPE_NULL (0). 1143 * 1144 * @return Returns 0 to indicate success. Otherwise an kerberos et 1145 * error code is returned, see krb5_get_error_message(). 1146 * 1147 * @ingroup krb5 1148 */ 1149 1150 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1151 krb5_set_default_in_tkt_etypes(krb5_context context, 1152 const krb5_enctype *etypes) 1153 { 1154 krb5_error_code ret; 1155 krb5_enctype *p = NULL; 1156 1157 if(etypes) { 1158 ret = copy_enctypes(context, etypes, &p); 1159 if (ret) 1160 return ret; 1161 } 1162 if (p == NULL) { 1163 krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, 1164 N_("entypes not supported", "")); 1165 return KRB5_PROG_ETYPE_NOSUPP; 1166 } 1167 if (context->etypes) 1168 free(context->etypes); 1169 context->etypes = p; 1170 return 0; 1171 } 1172 1173 /** 1174 * Get the default encryption types that will be use in communcation 1175 * with the KDC, clients and servers. 1176 * 1177 * @param context Kerberos 5 context. 1178 * @param etypes Encryption types, array terminated with 1179 * ETYPE_NULL(0), caller should free array with krb5_xfree(): 1180 * 1181 * @return Returns 0 to indicate success. Otherwise an kerberos et 1182 * error code is returned, see krb5_get_error_message(). 1183 * 1184 * @ingroup krb5 1185 */ 1186 1187 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1188 krb5_get_default_in_tkt_etypes(krb5_context context, 1189 krb5_pdu pdu_type, 1190 krb5_enctype **etypes) 1191 { 1192 krb5_enctype *enctypes = NULL; 1193 krb5_error_code ret; 1194 krb5_enctype *p; 1195 1196 heim_assert(pdu_type == KRB5_PDU_AS_REQUEST || 1197 pdu_type == KRB5_PDU_TGS_REQUEST || 1198 pdu_type == KRB5_PDU_NONE, "pdu contant not as expected"); 1199 1200 if (pdu_type == KRB5_PDU_AS_REQUEST && context->as_etypes != NULL) 1201 enctypes = context->as_etypes; 1202 else if (pdu_type == KRB5_PDU_TGS_REQUEST && context->tgs_etypes != NULL) 1203 enctypes = context->tgs_etypes; 1204 else if (context->etypes != NULL) 1205 enctypes = context->etypes; 1206 1207 if (enctypes != NULL) { 1208 ret = copy_enctypes(context, enctypes, &p); 1209 if (ret) 1210 return ret; 1211 } else { 1212 ret = default_etypes(context, &p); 1213 if (ret) 1214 return ret; 1215 } 1216 *etypes = p; 1217 return 0; 1218 } 1219 1220 /** 1221 * Init the built-in ets in the Kerberos library. 1222 * 1223 * @param context kerberos context to add the ets too 1224 * 1225 * @ingroup krb5 1226 */ 1227 1228 KRB5_LIB_FUNCTION void KRB5_LIB_CALL 1229 krb5_init_ets(krb5_context context) 1230 { 1231 if (context->et_list == NULL){ 1232 krb5_add_et_list(context, initialize_krb5_error_table_r); 1233 krb5_add_et_list(context, initialize_asn1_error_table_r); 1234 krb5_add_et_list(context, initialize_heim_error_table_r); 1235 1236 krb5_add_et_list(context, initialize_k524_error_table_r); 1237 1238 #ifdef COM_ERR_BINDDOMAIN_krb5 1239 bindtextdomain(COM_ERR_BINDDOMAIN_krb5, HEIMDAL_LOCALEDIR); 1240 bindtextdomain(COM_ERR_BINDDOMAIN_asn1, HEIMDAL_LOCALEDIR); 1241 bindtextdomain(COM_ERR_BINDDOMAIN_heim, HEIMDAL_LOCALEDIR); 1242 bindtextdomain(COM_ERR_BINDDOMAIN_k524, HEIMDAL_LOCALEDIR); 1243 #endif 1244 1245 #ifdef PKINIT 1246 krb5_add_et_list(context, initialize_hx_error_table_r); 1247 #ifdef COM_ERR_BINDDOMAIN_hx 1248 bindtextdomain(COM_ERR_BINDDOMAIN_hx, HEIMDAL_LOCALEDIR); 1249 #endif 1250 #endif 1251 } 1252 } 1253 1254 /** 1255 * Make the kerberos library default to the admin KDC. 1256 * 1257 * @param context Kerberos 5 context. 1258 * @param flag boolean flag to select if the use the admin KDC or not. 1259 * 1260 * @ingroup krb5 1261 */ 1262 1263 KRB5_LIB_FUNCTION void KRB5_LIB_CALL 1264 krb5_set_use_admin_kdc (krb5_context context, krb5_boolean flag) 1265 { 1266 context->use_admin_kdc = flag; 1267 } 1268 1269 /** 1270 * Make the kerberos library default to the admin KDC. 1271 * 1272 * @param context Kerberos 5 context. 1273 * 1274 * @return boolean flag to telling the context will use admin KDC as the default KDC. 1275 * 1276 * @ingroup krb5 1277 */ 1278 1279 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 1280 krb5_get_use_admin_kdc (krb5_context context) 1281 { 1282 return context->use_admin_kdc; 1283 } 1284 1285 /** 1286 * Add extra address to the address list that the library will add to 1287 * the client's address list when communicating with the KDC. 1288 * 1289 * @param context Kerberos 5 context. 1290 * @param addresses addreses to add 1291 * 1292 * @return Returns 0 to indicate success. Otherwise an kerberos et 1293 * error code is returned, see krb5_get_error_message(). 1294 * 1295 * @ingroup krb5 1296 */ 1297 1298 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1299 krb5_add_extra_addresses(krb5_context context, krb5_addresses *addresses) 1300 { 1301 1302 if (context->extra_addresses) 1303 return krb5_append_addresses(context, 1304 context->extra_addresses, addresses); 1305 else 1306 return krb5_set_extra_addresses(context, addresses); 1307 } 1308 1309 /** 1310 * Set extra address to the address list that the library will add to 1311 * the client's address list when communicating with the KDC. 1312 * 1313 * @param context Kerberos 5 context. 1314 * @param addresses addreses to set 1315 * 1316 * @return Returns 0 to indicate success. Otherwise an kerberos et 1317 * error code is returned, see krb5_get_error_message(). 1318 * 1319 * @ingroup krb5 1320 */ 1321 1322 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1323 krb5_set_extra_addresses(krb5_context context, const krb5_addresses *addresses) 1324 { 1325 if (context->extra_addresses) 1326 krb5_free_addresses(context, context->extra_addresses); 1327 1328 if (addresses == NULL) { 1329 if (context->extra_addresses != NULL) { 1330 free(context->extra_addresses); 1331 context->extra_addresses = NULL; 1332 } 1333 return 0; 1334 } 1335 if (context->extra_addresses == NULL) { 1336 context->extra_addresses = malloc(sizeof(*context->extra_addresses)); 1337 if (context->extra_addresses == NULL) { 1338 krb5_set_error_message (context, ENOMEM, N_("malloc: out of memory", "")); 1339 return ENOMEM; 1340 } 1341 } 1342 return krb5_copy_addresses(context, addresses, context->extra_addresses); 1343 } 1344 1345 /** 1346 * Get extra address to the address list that the library will add to 1347 * the client's address list when communicating with the KDC. 1348 * 1349 * @param context Kerberos 5 context. 1350 * @param addresses addreses to set 1351 * 1352 * @return Returns 0 to indicate success. Otherwise an kerberos et 1353 * error code is returned, see krb5_get_error_message(). 1354 * 1355 * @ingroup krb5 1356 */ 1357 1358 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1359 krb5_get_extra_addresses(krb5_context context, krb5_addresses *addresses) 1360 { 1361 if (context->extra_addresses == NULL) { 1362 memset(addresses, 0, sizeof(*addresses)); 1363 return 0; 1364 } 1365 return krb5_copy_addresses(context,context->extra_addresses, addresses); 1366 } 1367 1368 /** 1369 * Add extra addresses to ignore when fetching addresses from the 1370 * underlaying operating system. 1371 * 1372 * @param context Kerberos 5 context. 1373 * @param addresses addreses to ignore 1374 * 1375 * @return Returns 0 to indicate success. Otherwise an kerberos et 1376 * error code is returned, see krb5_get_error_message(). 1377 * 1378 * @ingroup krb5 1379 */ 1380 1381 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1382 krb5_add_ignore_addresses(krb5_context context, krb5_addresses *addresses) 1383 { 1384 1385 if (context->ignore_addresses) 1386 return krb5_append_addresses(context, 1387 context->ignore_addresses, addresses); 1388 else 1389 return krb5_set_ignore_addresses(context, addresses); 1390 } 1391 1392 /** 1393 * Set extra addresses to ignore when fetching addresses from the 1394 * underlaying operating system. 1395 * 1396 * @param context Kerberos 5 context. 1397 * @param addresses addreses to ignore 1398 * 1399 * @return Returns 0 to indicate success. Otherwise an kerberos et 1400 * error code is returned, see krb5_get_error_message(). 1401 * 1402 * @ingroup krb5 1403 */ 1404 1405 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1406 krb5_set_ignore_addresses(krb5_context context, const krb5_addresses *addresses) 1407 { 1408 if (context->ignore_addresses) 1409 krb5_free_addresses(context, context->ignore_addresses); 1410 if (addresses == NULL) { 1411 if (context->ignore_addresses != NULL) { 1412 free(context->ignore_addresses); 1413 context->ignore_addresses = NULL; 1414 } 1415 return 0; 1416 } 1417 if (context->ignore_addresses == NULL) { 1418 context->ignore_addresses = malloc(sizeof(*context->ignore_addresses)); 1419 if (context->ignore_addresses == NULL) { 1420 krb5_set_error_message (context, ENOMEM, N_("malloc: out of memory", "")); 1421 return ENOMEM; 1422 } 1423 } 1424 return krb5_copy_addresses(context, addresses, context->ignore_addresses); 1425 } 1426 1427 /** 1428 * Get extra addresses to ignore when fetching addresses from the 1429 * underlaying operating system. 1430 * 1431 * @param context Kerberos 5 context. 1432 * @param addresses list addreses ignored 1433 * 1434 * @return Returns 0 to indicate success. Otherwise an kerberos et 1435 * error code is returned, see krb5_get_error_message(). 1436 * 1437 * @ingroup krb5 1438 */ 1439 1440 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1441 krb5_get_ignore_addresses(krb5_context context, krb5_addresses *addresses) 1442 { 1443 if (context->ignore_addresses == NULL) { 1444 memset(addresses, 0, sizeof(*addresses)); 1445 return 0; 1446 } 1447 return krb5_copy_addresses(context, context->ignore_addresses, addresses); 1448 } 1449 1450 /** 1451 * Set version of fcache that the library should use. 1452 * 1453 * @param context Kerberos 5 context. 1454 * @param version version number. 1455 * 1456 * @return Returns 0 to indicate success. Otherwise an kerberos et 1457 * error code is returned, see krb5_get_error_message(). 1458 * 1459 * @ingroup krb5 1460 */ 1461 1462 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1463 krb5_set_fcache_version(krb5_context context, int version) 1464 { 1465 context->fcache_vno = version; 1466 return 0; 1467 } 1468 1469 /** 1470 * Get version of fcache that the library should use. 1471 * 1472 * @param context Kerberos 5 context. 1473 * @param version version number. 1474 * 1475 * @return Returns 0 to indicate success. Otherwise an kerberos et 1476 * error code is returned, see krb5_get_error_message(). 1477 * 1478 * @ingroup krb5 1479 */ 1480 1481 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1482 krb5_get_fcache_version(krb5_context context, int *version) 1483 { 1484 *version = context->fcache_vno; 1485 return 0; 1486 } 1487 1488 /** 1489 * Runtime check if the Kerberos library was complied with thread support. 1490 * 1491 * @return TRUE if the library was compiled with thread support, FALSE if not. 1492 * 1493 * @ingroup krb5 1494 */ 1495 1496 1497 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 1498 krb5_is_thread_safe(void) 1499 { 1500 #ifdef ENABLE_PTHREAD_SUPPORT 1501 return TRUE; 1502 #else 1503 return FALSE; 1504 #endif 1505 } 1506 1507 /** 1508 * Set if the library should use DNS to canonicalize hostnames. 1509 * 1510 * @param context Kerberos 5 context. 1511 * @param flag if its dns canonicalizion is used or not. 1512 * 1513 * @ingroup krb5 1514 */ 1515 1516 KRB5_LIB_FUNCTION void KRB5_LIB_CALL 1517 krb5_set_dns_canonicalize_hostname (krb5_context context, krb5_boolean flag) 1518 { 1519 if (flag) 1520 context->flags |= KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME; 1521 else 1522 context->flags &= ~KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME; 1523 } 1524 1525 /** 1526 * Get if the library uses DNS to canonicalize hostnames. 1527 * 1528 * @param context Kerberos 5 context. 1529 * 1530 * @return return non zero if the library uses DNS to canonicalize hostnames. 1531 * 1532 * @ingroup krb5 1533 */ 1534 1535 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 1536 krb5_get_dns_canonicalize_hostname (krb5_context context) 1537 { 1538 return (context->flags & KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME) ? 1 : 0; 1539 } 1540 1541 /** 1542 * Get current offset in time to the KDC. 1543 * 1544 * @param context Kerberos 5 context. 1545 * @param sec seconds part of offset. 1546 * @param usec micro seconds part of offset. 1547 * 1548 * @return returns zero 1549 * 1550 * @ingroup krb5 1551 */ 1552 1553 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1554 krb5_get_kdc_sec_offset (krb5_context context, int32_t *sec, int32_t *usec) 1555 { 1556 if (sec) 1557 *sec = context->kdc_sec_offset; 1558 if (usec) 1559 *usec = context->kdc_usec_offset; 1560 return 0; 1561 } 1562 1563 /** 1564 * Set current offset in time to the KDC. 1565 * 1566 * @param context Kerberos 5 context. 1567 * @param sec seconds part of offset. 1568 * @param usec micro seconds part of offset. 1569 * 1570 * @return returns zero 1571 * 1572 * @ingroup krb5 1573 */ 1574 1575 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1576 krb5_set_kdc_sec_offset (krb5_context context, int32_t sec, int32_t usec) 1577 { 1578 context->kdc_sec_offset = sec; 1579 if (usec >= 0) 1580 context->kdc_usec_offset = usec; 1581 return 0; 1582 } 1583 1584 /** 1585 * Get max time skew allowed. 1586 * 1587 * @param context Kerberos 5 context. 1588 * 1589 * @return timeskew in seconds. 1590 * 1591 * @ingroup krb5 1592 */ 1593 1594 KRB5_LIB_FUNCTION time_t KRB5_LIB_CALL 1595 krb5_get_max_time_skew (krb5_context context) 1596 { 1597 return context->max_skew; 1598 } 1599 1600 /** 1601 * Set max time skew allowed. 1602 * 1603 * @param context Kerberos 5 context. 1604 * @param t timeskew in seconds. 1605 * 1606 * @ingroup krb5 1607 */ 1608 1609 KRB5_LIB_FUNCTION void KRB5_LIB_CALL 1610 krb5_set_max_time_skew (krb5_context context, time_t t) 1611 { 1612 context->max_skew = t; 1613 } 1614 1615 /* 1616 * Init encryption types in len, val with etypes. 1617 * 1618 * @param context Kerberos 5 context. 1619 * @param pdu_type type of pdu 1620 * @param len output length of val. 1621 * @param val output array of enctypes. 1622 * @param etypes etypes to set val and len to, if NULL, use default enctypes. 1623 1624 * @return Returns 0 to indicate success. Otherwise an kerberos et 1625 * error code is returned, see krb5_get_error_message(). 1626 * 1627 * @ingroup krb5 1628 */ 1629 1630 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1631 _krb5_init_etype(krb5_context context, 1632 krb5_pdu pdu_type, 1633 unsigned *len, 1634 krb5_enctype **val, 1635 const krb5_enctype *etypes) 1636 { 1637 krb5_error_code ret; 1638 1639 if (etypes == NULL) 1640 ret = krb5_get_default_in_tkt_etypes(context, pdu_type, val); 1641 else 1642 ret = copy_enctypes(context, etypes, val); 1643 if (ret) 1644 return ret; 1645 1646 if (len) { 1647 *len = 0; 1648 while ((*val)[*len] != KRB5_ENCTYPE_NULL) 1649 (*len)++; 1650 } 1651 return 0; 1652 } 1653 1654 /* 1655 * Allow homedir accces 1656 */ 1657 1658 krb5_boolean 1659 krb5_homedir_access(krb5_context context) 1660 { 1661 krb5_boolean allow; 1662 1663 #ifdef HAVE_GETEUID 1664 /* is never allowed for root */ 1665 if (geteuid() == 0) 1666 return FALSE; 1667 #endif 1668 1669 if (context && (context->flags & KRB5_CTX_F_HOMEDIR_ACCESS) == 0) 1670 return FALSE; 1671 1672 HEIMDAL_MUTEX_lock(&homedir_mutex); 1673 allow = allow_homedir; 1674 HEIMDAL_MUTEX_unlock(&homedir_mutex); 1675 return allow; 1676 } 1677 1678 /** 1679 * Enable and disable home directory access on either the global state 1680 * or the krb5_context state. By calling krb5_set_home_dir_access() 1681 * with context set to NULL, the global state is configured otherwise 1682 * the state for the krb5_context is modified. 1683 * 1684 * For home directory access to be allowed, both the global state and 1685 * the krb5_context state have to be allowed. 1686 * 1687 * Administrator (root user), never uses the home directory. 1688 * 1689 * @param context a Kerberos 5 context or NULL 1690 * @param allow allow if TRUE home directory 1691 * @return the old value 1692 * 1693 * @ingroup krb5 1694 */ 1695 1696 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 1697 krb5_set_home_dir_access(krb5_context context, krb5_boolean allow) 1698 { 1699 krb5_boolean old; 1700 if (context) { 1701 old = (context->flags & KRB5_CTX_F_HOMEDIR_ACCESS) ? TRUE : FALSE; 1702 if (allow) 1703 context->flags |= KRB5_CTX_F_HOMEDIR_ACCESS; 1704 else 1705 context->flags &= ~KRB5_CTX_F_HOMEDIR_ACCESS; 1706 } else { 1707 HEIMDAL_MUTEX_lock(&homedir_mutex); 1708 old = allow_homedir; 1709 allow_homedir = allow; 1710 HEIMDAL_MUTEX_unlock(&homedir_mutex); 1711 } 1712 1713 return old; 1714 } 1715 1716 static krb5_boolean 1717 _krb5_need_to_reload(krb5_context context) 1718 { 1719 #ifdef HAVE_NOTIFY_H 1720 int check = 0, ret; 1721 1722 if (check_token != -1) { 1723 ret = notify_check(check_token, &check); 1724 if (ret == NOTIFY_STATUS_OK && check) { 1725 context->last_config_update = time(NULL); 1726 return TRUE; 1727 } 1728 } 1729 if (config_token != -1) { 1730 ret = notify_check(config_token, &check); 1731 if (ret == NOTIFY_STATUS_OK && check) { 1732 context->last_config_update = time(NULL); 1733 return TRUE; 1734 } 1735 } 1736 #endif 1737 /* because of the perfomance penalty we don't reload unless we know its needed */ 1738 return FALSE; 1739 } 1740 1741 /** 1742 * Reload the configuration files that was used last time, used when 1743 * they might have changed. Will only reload if know for sure that the 1744 * files need to be reloaded. 1745 * 1746 * @param context the krb5 context to reload 1747 * @param flags flag field, pass 0 for now 1748 * @param reread the configuration file was re-read, 1749 * NULL is valid if the caller doesn't want to 1750 * know if it was re-read or not. 1751 * 1752 * @return Returns 0 to indicate success. Otherwise an kerberos et 1753 * error code is returned, see krb5_get_error_message(). 1754 * 1755 * @ingroup krb5 1756 */ 1757 1758 krb5_error_code 1759 krb5_reload_config(krb5_context context, 1760 unsigned flags, 1761 krb5_boolean *reread) 1762 { 1763 krb5_error_code ret; 1764 krb5_config_binding *tmp = NULL; 1765 unsigned i; 1766 1767 /** 1768 * If function returns a failure, and reread is used, value of 1769 * reread is FALSE. 1770 */ 1771 1772 if (reread) 1773 *reread = FALSE; 1774 1775 if (_krb5_need_to_reload(context) == FALSE) 1776 return 0; 1777 1778 if (context->config_files == NULL) 1779 return 0; 1780 1781 for (i = 0; context->config_files[i]; i++) { 1782 ret = krb5_config_parse_file_multi(context, 1783 context->config_files[i], 1784 &tmp); 1785 if (ret != 0 && ret != ENOENT && ret != EACCES && ret != EPERM && ret != KRB5_CONFIG_BADFORMAT) { 1786 krb5_config_file_free(context, tmp); 1787 return ret; 1788 } 1789 } 1790 1791 if (reread) 1792 *reread = TRUE; 1793 1794 krb5_config_file_free(context, context->cf); 1795 context->cf = tmp; 1796 1797 return init_context_from_config_file(context); 1798 }