1 /* 2 * Copyright (c) 1997 - 2002 Kungliga Tekniska H�gskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include "krb5_locl.h" 35 #include <com_err.h> 36 37 RCSID("$Id: context.c,v 1.83.2.1 2004/08/20 15:30:24 lha Exp $"); 38 39 #define INIT_FIELD(C, T, E, D, F) \ 40 (C)->E = krb5_config_get_ ## T ## _default ((C), NULL, (D), \ 41 "libdefaults", F, NULL) 42 43 /* 44 * Set the list of etypes `ret_etypes' from the configuration variable 45 * `name' 46 */ 47 48 static krb5_error_code 49 set_etypes (krb5_context context, 50 const char *name, 51 krb5_enctype **ret_enctypes) 52 { 53 char **etypes_str; 54 krb5_enctype *etypes = NULL; 55 56 etypes_str = krb5_config_get_strings(context, NULL, "libdefaults", 57 name, NULL); 58 if(etypes_str){ 59 int i, j, k; 60 for(i = 0; etypes_str[i]; i++); 61 etypes = malloc((i+1) * sizeof(*etypes)); 62 if (etypes == NULL) { 63 krb5_config_free_strings (etypes_str); 64 krb5_set_error_string (context, "malloc: out of memory"); 65 return ENOMEM; 66 } 67 for(j = 0, k = 0; j < i; j++) { 68 if(krb5_string_to_enctype(context, etypes_str[j], &etypes[k]) == 0) 69 k++; 70 } 71 etypes[k] = ETYPE_NULL; 72 krb5_config_free_strings(etypes_str); 73 } 74 *ret_enctypes = etypes; 75 return 0; 76 } 77 78 /* 79 * read variables from the configuration file and set in `context' 80 */ 81 82 static krb5_error_code 83 init_context_from_config_file(krb5_context context) 84 { 85 krb5_error_code ret; 86 const char * tmp; 87 krb5_enctype *tmptypes; 88 89 INIT_FIELD(context, time, max_skew, 5 * 60, "clockskew"); 90 INIT_FIELD(context, time, kdc_timeout, 3, "kdc_timeout"); 91 INIT_FIELD(context, int, max_retries, 3, "max_retries"); 92 93 INIT_FIELD(context, string, http_proxy, NULL, "http_proxy"); 94 95 ret = set_etypes (context, "default_etypes", &tmptypes); 96 if(ret) 97 return ret; 98 free(context->etypes); 99 context->etypes = tmptypes; 100 101 ret = set_etypes (context, "default_etypes_des", &tmptypes); 102 if(ret) 103 return ret; 104 free(context->etypes_des); 105 context->etypes_des = tmptypes; 106 107 /* default keytab name */ 108 tmp = NULL; 109 if(!issuid()) 110 tmp = getenv("KRB5_KTNAME"); 111 if(tmp != NULL) 112 context->default_keytab = tmp; 113 else 114 INIT_FIELD(context, string, default_keytab, 115 KEYTAB_DEFAULT, "default_keytab_name"); 116 117 INIT_FIELD(context, string, default_keytab_modify, 118 NULL, "default_keytab_modify_name"); 119 120 INIT_FIELD(context, string, time_fmt, 121 "%Y-%m-%dT%H:%M:%S", "time_format"); 122 123 INIT_FIELD(context, string, date_fmt, 124 "%Y-%m-%d", "date_format"); 125 126 INIT_FIELD(context, bool, log_utc, 127 FALSE, "log_utc"); 128 129 130 131 /* init dns-proxy slime */ 132 tmp = krb5_config_get_string(context, NULL, "libdefaults", 133 "dns_proxy", NULL); 134 if(tmp) 135 roken_gethostby_setup(context->http_proxy, tmp); 136 krb5_free_host_realm (context, context->default_realms); 137 context->default_realms = NULL; 138 139 { 140 krb5_addresses addresses; 141 char **adr, **a; 142 143 krb5_set_extra_addresses(context, NULL); 144 adr = krb5_config_get_strings(context, NULL, 145 "libdefaults", 146 "extra_addresses", 147 NULL); 148 memset(&addresses, 0, sizeof(addresses)); 149 for(a = adr; a && *a; a++) { 150 ret = krb5_parse_address(context, *a, &addresses); 151 if (ret == 0) { 152 krb5_add_extra_addresses(context, &addresses); 153 krb5_free_addresses(context, &addresses); 154 } 155 } 156 krb5_config_free_strings(adr); 157 158 krb5_set_ignore_addresses(context, NULL); 159 adr = krb5_config_get_strings(context, NULL, 160 "libdefaults", 161 "ignore_addresses", 162 NULL); 163 memset(&addresses, 0, sizeof(addresses)); 164 for(a = adr; a && *a; a++) { 165 ret = krb5_parse_address(context, *a, &addresses); 166 if (ret == 0) { 167 krb5_add_ignore_addresses(context, &addresses); 168 krb5_free_addresses(context, &addresses); 169 } 170 } 171 krb5_config_free_strings(adr); 172 } 173 174 INIT_FIELD(context, bool, scan_interfaces, TRUE, "scan_interfaces"); 175 INIT_FIELD(context, int, fcache_vno, 0, "fcache_version"); 176 /* prefer dns_lookup_kdc over srv_lookup. */ 177 INIT_FIELD(context, bool, srv_lookup, TRUE, "srv_lookup"); 178 INIT_FIELD(context, bool, srv_lookup, context->srv_lookup, "dns_lookup_kdc"); 179 context->default_cc_name = NULL; 180 return 0; 181 } 182 183 krb5_error_code 184 krb5_init_context(krb5_context *context) 185 { 186 krb5_context p; 187 krb5_error_code ret; 188 char **files; 189 190 p = calloc(1, sizeof(*p)); 191 if(!p) 192 return ENOMEM; 193 194 ret = krb5_get_default_config_files(&files); 195 if(ret) 196 goto out; 197 ret = krb5_set_config_files(p, files); 198 krb5_free_config_files(files); 199 if(ret) 200 goto out; 201 202 /* init error tables */ 203 krb5_init_ets(p); 204 205 p->cc_ops = NULL; 206 p->num_cc_ops = 0; 207 krb5_cc_register(p, &krb5_fcc_ops, TRUE); 208 krb5_cc_register(p, &krb5_mcc_ops, TRUE); 209 210 p->num_kt_types = 0; 211 p->kt_types = NULL; 212 krb5_kt_register (p, &krb5_fkt_ops); 213 krb5_kt_register (p, &krb5_mkt_ops); 214 krb5_kt_register (p, &krb5_akf_ops); 215 krb5_kt_register (p, &krb4_fkt_ops); 216 krb5_kt_register (p, &krb5_srvtab_fkt_ops); 217 krb5_kt_register (p, &krb5_any_ops); 218 219 out: 220 if(ret) { 221 krb5_free_context(p); 222 p = NULL; 223 } 224 *context = p; 225 return ret; 226 } 227 228 void 229 krb5_free_context(krb5_context context) 230 { 231 if (context->default_cc_name) 232 free(context->default_cc_name); 233 free(context->etypes); 234 free(context->etypes_des); 235 krb5_free_host_realm (context, context->default_realms); 236 krb5_config_file_free (context, context->cf); 237 free_error_table (context->et_list); 238 free(context->cc_ops); 239 free(context->kt_types); 240 krb5_clear_error_string(context); 241 if(context->warn_dest != NULL) 242 krb5_closelog(context, context->warn_dest); 243 krb5_set_extra_addresses(context, NULL); 244 krb5_set_ignore_addresses(context, NULL); 245 free(context); 246 } 247 248 krb5_error_code 249 krb5_set_config_files(krb5_context context, char **filenames) 250 { 251 krb5_error_code ret; 252 krb5_config_binding *tmp = NULL; 253 while(filenames != NULL && *filenames != NULL && **filenames != '\0') { 254 ret = krb5_config_parse_file_multi(context, *filenames, &tmp); 255 if(ret != 0 && ret != ENOENT) { 256 krb5_config_file_free(context, tmp); 257 return ret; 258 } 259 filenames++; 260 } 261 #if 0 262 /* with this enabled and if there are no config files, Kerberos is 263 considererd disabled */ 264 if(tmp == NULL) 265 return ENXIO; 266 #endif 267 krb5_config_file_free(context, context->cf); 268 context->cf = tmp; 269 ret = init_context_from_config_file(context); 270 return ret; 271 } 272 273 krb5_error_code 274 krb5_get_default_config_files(char ***pfilenames) 275 { 276 const char *p, *q; 277 char **pp; 278 int n, i; 279 280 const char *files = NULL; 281 if (pfilenames == NULL) 282 return EINVAL; 283 if(!issuid()) 284 files = getenv("KRB5_CONFIG"); 285 if (files == NULL) 286 files = krb5_config_file; 287 288 for(n = 0, p = files; strsep_copy(&p, ":", NULL, 0) != -1; n++); 289 pp = malloc((n + 1) * sizeof(*pp)); 290 if(pp == NULL) 291 return ENOMEM; 292 293 n = 0; 294 p = files; 295 while(1) { 296 ssize_t l; 297 q = p; 298 l = strsep_copy(&q, ":", NULL, 0); 299 if(l == -1) 300 break; 301 pp[n] = malloc(l + 1); 302 if(pp[n] == NULL) { 303 krb5_free_config_files(pp); 304 return ENOMEM; 305 } 306 l = strsep_copy(&p, ":", pp[n], l + 1); 307 for(i = 0; i < n; i++) 308 if(strcmp(pp[i], pp[n]) == 0) { 309 free(pp[n]); 310 goto skip; 311 } 312 n++; 313 skip:; 314 } 315 pp[n] = NULL; 316 *pfilenames = pp; 317 return 0; 318 } 319 320 void 321 krb5_free_config_files(char **filenames) 322 { 323 char **p; 324 for(p = filenames; *p != NULL; p++) 325 free(*p); 326 free(filenames); 327 } 328 329 /* 330 * set `etype' to a malloced list of the default enctypes 331 */ 332 333 static krb5_error_code 334 default_etypes(krb5_context context, krb5_enctype **etype) 335 { 336 krb5_enctype p[] = { 337 ETYPE_DES3_CBC_SHA1, 338 ETYPE_DES3_CBC_MD5, 339 ETYPE_ARCFOUR_HMAC_MD5, 340 ETYPE_DES_CBC_MD5, 341 ETYPE_DES_CBC_MD4, 342 ETYPE_DES_CBC_CRC, 343 ETYPE_NULL 344 }; 345 346 *etype = malloc(sizeof(p)); 347 if(*etype == NULL) { 348 krb5_set_error_string (context, "malloc: out of memory"); 349 return ENOMEM; 350 } 351 memcpy(*etype, p, sizeof(p)); 352 return 0; 353 } 354 355 krb5_error_code 356 krb5_set_default_in_tkt_etypes(krb5_context context, 357 const krb5_enctype *etypes) 358 { 359 int i; 360 krb5_enctype *p = NULL; 361 362 if(etypes) { 363 for (i = 0; etypes[i]; ++i) 364 if(!krb5_enctype_valid(context, etypes[i])) { 365 krb5_set_error_string(context, "enctype %d not supported", 366 etypes[i]); 367 return KRB5_PROG_ETYPE_NOSUPP; 368 } 369 ++i; 370 ALLOC(p, i); 371 if(!p) { 372 krb5_set_error_string (context, "malloc: out of memory"); 373 return ENOMEM; 374 } 375 memmove(p, etypes, i * sizeof(krb5_enctype)); 376 } 377 if(context->etypes) 378 free(context->etypes); 379 context->etypes = p; 380 return 0; 381 } 382 383 384 krb5_error_code 385 krb5_get_default_in_tkt_etypes(krb5_context context, 386 krb5_enctype **etypes) 387 { 388 krb5_enctype *p; 389 int i; 390 krb5_error_code ret; 391 392 if(context->etypes) { 393 for(i = 0; context->etypes[i]; i++); 394 ++i; 395 ALLOC(p, i); 396 if(!p) { 397 krb5_set_error_string (context, "malloc: out of memory"); 398 return ENOMEM; 399 } 400 memmove(p, context->etypes, i * sizeof(krb5_enctype)); 401 } else { 402 ret = default_etypes(context, &p); 403 if (ret) 404 return ret; 405 } 406 *etypes = p; 407 return 0; 408 } 409 410 const char * 411 krb5_get_err_text(krb5_context context, krb5_error_code code) 412 { 413 const char *p = NULL; 414 if(context != NULL) 415 p = com_right(context->et_list, code); 416 if(p == NULL) 417 p = strerror(code); 418 if (p == NULL) 419 p = "Unknown error"; 420 return p; 421 } 422 423 void 424 krb5_init_ets(krb5_context context) 425 { 426 if(context->et_list == NULL){ 427 krb5_add_et_list(context, initialize_krb5_error_table_r); 428 krb5_add_et_list(context, initialize_asn1_error_table_r); 429 krb5_add_et_list(context, initialize_heim_error_table_r); 430 krb5_add_et_list(context, initialize_k524_error_table_r); 431 } 432 } 433 434 void 435 krb5_set_use_admin_kdc (krb5_context context, krb5_boolean flag) 436 { 437 context->use_admin_kdc = flag; 438 } 439 440 krb5_boolean 441 krb5_get_use_admin_kdc (krb5_context context) 442 { 443 return context->use_admin_kdc; 444 } 445 446 krb5_error_code 447 krb5_add_extra_addresses(krb5_context context, krb5_addresses *addresses) 448 { 449 450 if(context->extra_addresses) 451 return krb5_append_addresses(context, 452 context->extra_addresses, addresses); 453 else 454 return krb5_set_extra_addresses(context, addresses); 455 } 456 457 krb5_error_code 458 krb5_set_extra_addresses(krb5_context context, const krb5_addresses *addresses) 459 { 460 if(context->extra_addresses) 461 krb5_free_addresses(context, context->extra_addresses); 462 463 if(addresses == NULL) { 464 if(context->extra_addresses != NULL) { 465 free(context->extra_addresses); 466 context->extra_addresses = NULL; 467 } 468 return 0; 469 } 470 if(context->extra_addresses == NULL) { 471 context->extra_addresses = malloc(sizeof(*context->extra_addresses)); 472 if(context->extra_addresses == NULL) { 473 krb5_set_error_string (context, "malloc: out of memory"); 474 return ENOMEM; 475 } 476 } 477 return krb5_copy_addresses(context, addresses, context->extra_addresses); 478 } 479 480 krb5_error_code 481 krb5_get_extra_addresses(krb5_context context, krb5_addresses *addresses) 482 { 483 if(context->extra_addresses == NULL) { 484 memset(addresses, 0, sizeof(*addresses)); 485 return 0; 486 } 487 return krb5_copy_addresses(context,context->extra_addresses, addresses); 488 } 489 490 krb5_error_code 491 krb5_add_ignore_addresses(krb5_context context, krb5_addresses *addresses) 492 { 493 494 if(context->ignore_addresses) 495 return krb5_append_addresses(context, 496 context->ignore_addresses, addresses); 497 else 498 return krb5_set_ignore_addresses(context, addresses); 499 } 500 501 krb5_error_code 502 krb5_set_ignore_addresses(krb5_context context, const krb5_addresses *addresses) 503 { 504 if(context->ignore_addresses) 505 krb5_free_addresses(context, context->ignore_addresses); 506 if(addresses == NULL) { 507 if(context->ignore_addresses != NULL) { 508 free(context->ignore_addresses); 509 context->ignore_addresses = NULL; 510 } 511 return 0; 512 } 513 if(context->ignore_addresses == NULL) { 514 context->ignore_addresses = malloc(sizeof(*context->ignore_addresses)); 515 if(context->ignore_addresses == NULL) { 516 krb5_set_error_string (context, "malloc: out of memory"); 517 return ENOMEM; 518 } 519 } 520 return krb5_copy_addresses(context, addresses, context->ignore_addresses); 521 } 522 523 krb5_error_code 524 krb5_get_ignore_addresses(krb5_context context, krb5_addresses *addresses) 525 { 526 if(context->ignore_addresses == NULL) { 527 memset(addresses, 0, sizeof(*addresses)); 528 return 0; 529 } 530 return krb5_copy_addresses(context, context->ignore_addresses, addresses); 531 } 532 533 krb5_error_code 534 krb5_set_fcache_version(krb5_context context, int version) 535 { 536 context->fcache_vno = version; 537 return 0; 538 } 539 540 krb5_error_code 541 krb5_get_fcache_version(krb5_context context, int *version) 542 { 543 *version = context->fcache_vno; 544 return 0; 545 } 546