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.81 2002/09/02 17:03:12 joda 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 return 0; 180 } 181 182 krb5_error_code 183 krb5_init_context(krb5_context *context) 184 { 185 krb5_context p; 186 krb5_error_code ret; 187 char **files; 188 189 p = calloc(1, sizeof(*p)); 190 if(!p) 191 return ENOMEM; 192 193 ret = krb5_get_default_config_files(&files); 194 if(ret) 195 goto out; 196 ret = krb5_set_config_files(p, files); 197 krb5_free_config_files(files); 198 if(ret) 199 goto out; 200 201 /* init error tables */ 202 krb5_init_ets(p); 203 204 p->cc_ops = NULL; 205 p->num_cc_ops = 0; 206 krb5_cc_register(p, &krb5_fcc_ops, TRUE); 207 krb5_cc_register(p, &krb5_mcc_ops, TRUE); 208 209 p->num_kt_types = 0; 210 p->kt_types = NULL; 211 krb5_kt_register (p, &krb5_fkt_ops); 212 krb5_kt_register (p, &krb5_mkt_ops); 213 krb5_kt_register (p, &krb5_akf_ops); 214 krb5_kt_register (p, &krb4_fkt_ops); 215 krb5_kt_register (p, &krb5_srvtab_fkt_ops); 216 krb5_kt_register (p, &krb5_any_ops); 217 218 out: 219 if(ret) { 220 krb5_free_context(p); 221 p = NULL; 222 } 223 *context = p; 224 return ret; 225 } 226 227 void 228 krb5_free_context(krb5_context context) 229 { 230 free(context->etypes); 231 free(context->etypes_des); 232 krb5_free_host_realm (context, context->default_realms); 233 krb5_config_file_free (context, context->cf); 234 free_error_table (context->et_list); 235 free(context->cc_ops); 236 free(context->kt_types); 237 krb5_clear_error_string(context); 238 if(context->warn_dest != NULL) 239 krb5_closelog(context, context->warn_dest); 240 krb5_set_extra_addresses(context, NULL); 241 krb5_set_ignore_addresses(context, NULL); 242 free(context); 243 } 244 245 krb5_error_code 246 krb5_set_config_files(krb5_context context, char **filenames) 247 { 248 krb5_error_code ret; 249 krb5_config_binding *tmp = NULL; 250 while(filenames != NULL && *filenames != NULL && **filenames != '\0') { 251 ret = krb5_config_parse_file_multi(context, *filenames, &tmp); 252 if(ret != 0 && ret != ENOENT) { 253 krb5_config_file_free(context, tmp); 254 return ret; 255 } 256 filenames++; 257 } 258 #if 0 259 /* with this enabled and if there are no config files, Kerberos is 260 considererd disabled */ 261 if(tmp == NULL) 262 return ENOENT; 263 #endif 264 krb5_config_file_free(context, context->cf); 265 context->cf = tmp; 266 ret = init_context_from_config_file(context); 267 return ret; 268 } 269 270 krb5_error_code 271 krb5_get_default_config_files(char ***pfilenames) 272 { 273 const char *p, *q; 274 char **pp; 275 int n, i; 276 277 const char *files = NULL; 278 if (pfilenames == NULL) 279 return EINVAL; 280 if(!issuid()) 281 files = getenv("KRB5_CONFIG"); 282 if (files == NULL) 283 files = krb5_config_file; 284 285 for(n = 0, p = files; strsep_copy(&p, ":", NULL, 0) != -1; n++); 286 pp = malloc((n + 1) * sizeof(*pp)); 287 if(pp == NULL) 288 return ENOMEM; 289 290 n = 0; 291 p = files; 292 while(1) { 293 ssize_t l; 294 q = p; 295 l = strsep_copy(&q, ":", NULL, 0); 296 if(l == -1) 297 break; 298 pp[n] = malloc(l + 1); 299 if(pp[n] == NULL) { 300 krb5_free_config_files(pp); 301 return ENOMEM; 302 } 303 l = strsep_copy(&p, ":", pp[n], l + 1); 304 for(i = 0; i < n; i++) 305 if(strcmp(pp[i], pp[n]) == 0) { 306 free(pp[n]); 307 goto skip; 308 } 309 n++; 310 skip:; 311 } 312 pp[n] = NULL; 313 *pfilenames = pp; 314 return 0; 315 } 316 317 void 318 krb5_free_config_files(char **filenames) 319 { 320 char **p; 321 for(p = filenames; *p != NULL; p++) 322 free(*p); 323 free(filenames); 324 } 325 326 /* 327 * set `etype' to a malloced list of the default enctypes 328 */ 329 330 static krb5_error_code 331 default_etypes(krb5_context context, krb5_enctype **etype) 332 { 333 krb5_enctype p[] = { 334 ETYPE_DES3_CBC_SHA1, 335 ETYPE_DES3_CBC_MD5, 336 ETYPE_ARCFOUR_HMAC_MD5, 337 ETYPE_DES_CBC_MD5, 338 ETYPE_DES_CBC_MD4, 339 ETYPE_DES_CBC_CRC, 340 ETYPE_NULL 341 }; 342 343 *etype = malloc(sizeof(p)); 344 if(*etype == NULL) { 345 krb5_set_error_string (context, "malloc: out of memory"); 346 return ENOMEM; 347 } 348 memcpy(*etype, p, sizeof(p)); 349 return 0; 350 } 351 352 krb5_error_code 353 krb5_set_default_in_tkt_etypes(krb5_context context, 354 const krb5_enctype *etypes) 355 { 356 int i; 357 krb5_enctype *p = NULL; 358 359 if(etypes) { 360 for (i = 0; etypes[i]; ++i) 361 if(!krb5_enctype_valid(context, etypes[i])) { 362 krb5_set_error_string(context, "enctype %d not supported", 363 etypes[i]); 364 return KRB5_PROG_ETYPE_NOSUPP; 365 } 366 ++i; 367 ALLOC(p, i); 368 if(!p) { 369 krb5_set_error_string (context, "malloc: out of memory"); 370 return ENOMEM; 371 } 372 memmove(p, etypes, i * sizeof(krb5_enctype)); 373 } 374 if(context->etypes) 375 free(context->etypes); 376 context->etypes = p; 377 return 0; 378 } 379 380 381 krb5_error_code 382 krb5_get_default_in_tkt_etypes(krb5_context context, 383 krb5_enctype **etypes) 384 { 385 krb5_enctype *p; 386 int i; 387 krb5_error_code ret; 388 389 if(context->etypes) { 390 for(i = 0; context->etypes[i]; i++); 391 ++i; 392 ALLOC(p, i); 393 if(!p) { 394 krb5_set_error_string (context, "malloc: out of memory"); 395 return ENOMEM; 396 } 397 memmove(p, context->etypes, i * sizeof(krb5_enctype)); 398 } else { 399 ret = default_etypes(context, &p); 400 if (ret) 401 return ret; 402 } 403 *etypes = p; 404 return 0; 405 } 406 407 const char * 408 krb5_get_err_text(krb5_context context, krb5_error_code code) 409 { 410 const char *p = NULL; 411 if(context != NULL) 412 p = com_right(context->et_list, code); 413 if(p == NULL) 414 p = strerror(code); 415 return p; 416 } 417 418 void 419 krb5_init_ets(krb5_context context) 420 { 421 if(context->et_list == NULL){ 422 krb5_add_et_list(context, initialize_krb5_error_table_r); 423 krb5_add_et_list(context, initialize_asn1_error_table_r); 424 krb5_add_et_list(context, initialize_heim_error_table_r); 425 krb5_add_et_list(context, initialize_k524_error_table_r); 426 } 427 } 428 429 void 430 krb5_set_use_admin_kdc (krb5_context context, krb5_boolean flag) 431 { 432 context->use_admin_kdc = flag; 433 } 434 435 krb5_boolean 436 krb5_get_use_admin_kdc (krb5_context context) 437 { 438 return context->use_admin_kdc; 439 } 440 441 krb5_error_code 442 krb5_add_extra_addresses(krb5_context context, krb5_addresses *addresses) 443 { 444 445 if(context->extra_addresses) 446 return krb5_append_addresses(context, 447 context->extra_addresses, addresses); 448 else 449 return krb5_set_extra_addresses(context, addresses); 450 } 451 452 krb5_error_code 453 krb5_set_extra_addresses(krb5_context context, const krb5_addresses *addresses) 454 { 455 if(context->extra_addresses) 456 krb5_free_addresses(context, context->extra_addresses); 457 458 if(addresses == NULL) { 459 if(context->extra_addresses != NULL) { 460 free(context->extra_addresses); 461 context->extra_addresses = NULL; 462 } 463 return 0; 464 } 465 if(context->extra_addresses == NULL) { 466 context->extra_addresses = malloc(sizeof(*context->extra_addresses)); 467 if(context->extra_addresses == NULL) { 468 krb5_set_error_string (context, "malloc: out of memory"); 469 return ENOMEM; 470 } 471 } 472 return krb5_copy_addresses(context, addresses, context->extra_addresses); 473 } 474 475 krb5_error_code 476 krb5_get_extra_addresses(krb5_context context, krb5_addresses *addresses) 477 { 478 if(context->extra_addresses == NULL) { 479 memset(addresses, 0, sizeof(*addresses)); 480 return 0; 481 } 482 return krb5_copy_addresses(context,context->extra_addresses, addresses); 483 } 484 485 krb5_error_code 486 krb5_add_ignore_addresses(krb5_context context, krb5_addresses *addresses) 487 { 488 489 if(context->ignore_addresses) 490 return krb5_append_addresses(context, 491 context->ignore_addresses, addresses); 492 else 493 return krb5_set_ignore_addresses(context, addresses); 494 } 495 496 krb5_error_code 497 krb5_set_ignore_addresses(krb5_context context, const krb5_addresses *addresses) 498 { 499 if(context->ignore_addresses) 500 krb5_free_addresses(context, context->ignore_addresses); 501 if(addresses == NULL) { 502 if(context->ignore_addresses != NULL) { 503 free(context->ignore_addresses); 504 context->ignore_addresses = NULL; 505 } 506 return 0; 507 } 508 if(context->ignore_addresses == NULL) { 509 context->ignore_addresses = malloc(sizeof(*context->ignore_addresses)); 510 if(context->ignore_addresses == NULL) { 511 krb5_set_error_string (context, "malloc: out of memory"); 512 return ENOMEM; 513 } 514 } 515 return krb5_copy_addresses(context, addresses, context->ignore_addresses); 516 } 517 518 krb5_error_code 519 krb5_get_ignore_addresses(krb5_context context, krb5_addresses *addresses) 520 { 521 if(context->ignore_addresses == NULL) { 522 memset(addresses, 0, sizeof(*addresses)); 523 return 0; 524 } 525 return krb5_copy_addresses(context, context->ignore_addresses, addresses); 526 } 527 528 krb5_error_code 529 krb5_set_fcache_version(krb5_context context, int version) 530 { 531 context->fcache_vno = version; 532 return 0; 533 } 534 535 krb5_error_code 536 krb5_get_fcache_version(krb5_context context, int *version) 537 { 538 *version = context->fcache_vno; 539 return 0; 540 } 541