1 /* 2 * Copyright (c) 1997 - 2004 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 38 #ifdef __APPLE__ 39 #include <CoreFoundation/CoreFoundation.h> 40 #endif 41 42 /* Gaah! I want a portable funopen */ 43 struct fileptr { 44 const char *s; 45 FILE *f; 46 }; 47 48 static char * 49 config_fgets(char *str, size_t len, struct fileptr *ptr) 50 { 51 /* XXX this is not correct, in that they don't do the same if the 52 line is longer than len */ 53 if(ptr->f != NULL) 54 return fgets(str, len, ptr->f); 55 else { 56 /* this is almost strsep_copy */ 57 const char *p; 58 ssize_t l; 59 if(*ptr->s == '\0') 60 return NULL; 61 p = ptr->s + strcspn(ptr->s, "\n"); 62 if(*p == '\n') 63 p++; 64 l = min(len, (size_t)(p - ptr->s)); 65 if(len > 0) { 66 memcpy(str, ptr->s, l); 67 str[l] = '\0'; 68 } 69 ptr->s = p; 70 return str; 71 } 72 } 73 74 static krb5_error_code parse_section(char *p, krb5_config_section **s, 75 krb5_config_section **res, 76 const char **err_message); 77 static krb5_error_code parse_binding(struct fileptr *f, unsigned *lineno, char *p, 78 krb5_config_binding **b, 79 krb5_config_binding **parent, 80 const char **err_message); 81 static krb5_error_code parse_list(struct fileptr *f, unsigned *lineno, 82 krb5_config_binding **parent, 83 const char **err_message); 84 85 krb5_config_section * 86 _krb5_config_get_entry(krb5_config_section **parent, const char *name, int type) 87 { 88 krb5_config_section **q; 89 90 for(q = parent; *q != NULL; q = &(*q)->next) 91 if(type == krb5_config_list && 92 (unsigned)type == (*q)->type && 93 strcmp(name, (*q)->name) == 0) 94 return *q; 95 *q = calloc(1, sizeof(**q)); 96 if(*q == NULL) 97 return NULL; 98 (*q)->name = strdup(name); 99 (*q)->type = type; 100 if((*q)->name == NULL) { 101 free(*q); 102 *q = NULL; 103 return NULL; 104 } 105 return *q; 106 } 107 108 /* 109 * Parse a section: 110 * 111 * [section] 112 * foo = bar 113 * b = { 114 * a 115 * } 116 * ... 117 * 118 * starting at the line in `p', storing the resulting structure in 119 * `s' and hooking it into `parent'. 120 * Store the error message in `err_message'. 121 */ 122 123 static krb5_error_code 124 parse_section(char *p, krb5_config_section **s, krb5_config_section **parent, 125 const char **err_message) 126 { 127 char *p1; 128 krb5_config_section *tmp; 129 130 p1 = strchr (p + 1, ']'); 131 if (p1 == NULL) { 132 *err_message = "missing ]"; 133 return KRB5_CONFIG_BADFORMAT; 134 } 135 *p1 = '\0'; 136 tmp = _krb5_config_get_entry(parent, p + 1, krb5_config_list); 137 if(tmp == NULL) { 138 *err_message = "out of memory"; 139 return KRB5_CONFIG_BADFORMAT; 140 } 141 *s = tmp; 142 return 0; 143 } 144 145 /* 146 * Parse a brace-enclosed list from `f', hooking in the structure at 147 * `parent'. 148 * Store the error message in `err_message'. 149 */ 150 151 static krb5_error_code 152 parse_list(struct fileptr *f, unsigned *lineno, krb5_config_binding **parent, 153 const char **err_message) 154 { 155 char buf[KRB5_BUFSIZ]; 156 krb5_error_code ret; 157 krb5_config_binding *b = NULL; 158 unsigned beg_lineno = *lineno; 159 160 while(config_fgets(buf, sizeof(buf), f) != NULL) { 161 char *p; 162 163 ++*lineno; 164 buf[strcspn(buf, "\r\n")] = '\0'; 165 p = buf; 166 while(isspace((unsigned char)*p)) 167 ++p; 168 if (*p == '#' || *p == ';' || *p == '\0') 169 continue; 170 while(isspace((unsigned char)*p)) 171 ++p; 172 if (*p == '}') 173 return 0; 174 if (*p == '\0') 175 continue; 176 ret = parse_binding (f, lineno, p, &b, parent, err_message); 177 if (ret) 178 return ret; 179 } 180 *lineno = beg_lineno; 181 *err_message = "unclosed {"; 182 return KRB5_CONFIG_BADFORMAT; 183 } 184 185 /* 186 * 187 */ 188 189 static krb5_error_code 190 parse_binding(struct fileptr *f, unsigned *lineno, char *p, 191 krb5_config_binding **b, krb5_config_binding **parent, 192 const char **err_message) 193 { 194 krb5_config_binding *tmp; 195 char *p1, *p2; 196 krb5_error_code ret = 0; 197 198 p1 = p; 199 while (*p && *p != '=' && !isspace((unsigned char)*p)) 200 ++p; 201 if (*p == '\0') { 202 *err_message = "missing ="; 203 return KRB5_CONFIG_BADFORMAT; 204 } 205 p2 = p; 206 while (isspace((unsigned char)*p)) 207 ++p; 208 if (*p != '=') { 209 *err_message = "missing ="; 210 return KRB5_CONFIG_BADFORMAT; 211 } 212 ++p; 213 while(isspace((unsigned char)*p)) 214 ++p; 215 *p2 = '\0'; 216 if (*p == '{') { 217 tmp = _krb5_config_get_entry(parent, p1, krb5_config_list); 218 if (tmp == NULL) { 219 *err_message = "out of memory"; 220 return KRB5_CONFIG_BADFORMAT; 221 } 222 ret = parse_list (f, lineno, &tmp->u.list, err_message); 223 } else { 224 tmp = _krb5_config_get_entry(parent, p1, krb5_config_string); 225 if (tmp == NULL) { 226 *err_message = "out of memory"; 227 return KRB5_CONFIG_BADFORMAT; 228 } 229 p1 = p; 230 p = p1 + strlen(p1); 231 while(p > p1 && isspace((unsigned char)*(p-1))) 232 --p; 233 *p = '\0'; 234 tmp->u.string = strdup(p1); 235 } 236 *b = tmp; 237 return ret; 238 } 239 240 #if defined(__APPLE__) 241 242 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 243 #define HAVE_CFPROPERTYLISTCREATEWITHSTREAM 1 244 #endif 245 246 static char * 247 cfstring2cstring(CFStringRef string) 248 { 249 CFIndex len; 250 char *str; 251 252 str = (char *) CFStringGetCStringPtr(string, kCFStringEncodingUTF8); 253 if (str) 254 return strdup(str); 255 256 len = CFStringGetLength(string); 257 len = 1 + CFStringGetMaximumSizeForEncoding(len, kCFStringEncodingUTF8); 258 str = malloc(len); 259 if (str == NULL) 260 return NULL; 261 262 if (!CFStringGetCString (string, str, len, kCFStringEncodingUTF8)) { 263 free (str); 264 return NULL; 265 } 266 return str; 267 } 268 269 static void 270 convert_content(const void *key, const void *value, void *context) 271 { 272 krb5_config_section *tmp, **parent = context; 273 char *k; 274 275 if (CFGetTypeID(key) != CFStringGetTypeID()) 276 return; 277 278 k = cfstring2cstring(key); 279 if (k == NULL) 280 return; 281 282 if (CFGetTypeID(value) == CFStringGetTypeID()) { 283 tmp = _krb5_config_get_entry(parent, k, krb5_config_string); 284 tmp->u.string = cfstring2cstring(value); 285 } else if (CFGetTypeID(value) == CFDictionaryGetTypeID()) { 286 tmp = _krb5_config_get_entry(parent, k, krb5_config_list); 287 CFDictionaryApplyFunction(value, convert_content, &tmp->u.list); 288 } else { 289 /* log */ 290 } 291 free(k); 292 } 293 294 static krb5_error_code 295 parse_plist_config(krb5_context context, const char *path, krb5_config_section **parent) 296 { 297 CFReadStreamRef s; 298 CFDictionaryRef d; 299 CFURLRef url; 300 301 url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (UInt8 *)path, strlen(path), FALSE); 302 if (url == NULL) { 303 krb5_clear_error_message(context); 304 return ENOMEM; 305 } 306 307 s = CFReadStreamCreateWithFile(kCFAllocatorDefault, url); 308 CFRelease(url); 309 if (s == NULL) { 310 krb5_clear_error_message(context); 311 return ENOMEM; 312 } 313 314 if (!CFReadStreamOpen(s)) { 315 CFRelease(s); 316 krb5_clear_error_message(context); 317 return ENOENT; 318 } 319 320 #ifdef HAVE_CFPROPERTYLISTCREATEWITHSTREAM 321 d = (CFDictionaryRef)CFPropertyListCreateWithStream(NULL, s, 0, kCFPropertyListImmutable, NULL, NULL); 322 #else 323 d = (CFDictionaryRef)CFPropertyListCreateFromStream(NULL, s, 0, kCFPropertyListImmutable, NULL, NULL); 324 #endif 325 CFRelease(s); 326 if (d == NULL) { 327 krb5_clear_error_message(context); 328 return ENOENT; 329 } 330 331 CFDictionaryApplyFunction(d, convert_content, parent); 332 CFRelease(d); 333 334 return 0; 335 } 336 337 #endif 338 339 340 /* 341 * Parse the config file `fname', generating the structures into `res' 342 * returning error messages in `err_message' 343 */ 344 345 static krb5_error_code 346 krb5_config_parse_debug (struct fileptr *f, 347 krb5_config_section **res, 348 unsigned *lineno, 349 const char **err_message) 350 { 351 krb5_config_section *s = NULL; 352 krb5_config_binding *b = NULL; 353 char buf[KRB5_BUFSIZ]; 354 krb5_error_code ret; 355 356 while (config_fgets(buf, sizeof(buf), f) != NULL) { 357 char *p; 358 359 ++*lineno; 360 buf[strcspn(buf, "\r\n")] = '\0'; 361 p = buf; 362 while(isspace((unsigned char)*p)) 363 ++p; 364 if (*p == '#' || *p == ';') 365 continue; 366 if (*p == '[') { 367 ret = parse_section(p, &s, res, err_message); 368 if (ret) 369 return ret; 370 b = NULL; 371 } else if (*p == '}') { 372 *err_message = "unmatched }"; 373 return EINVAL; /* XXX */ 374 } else if(*p != '\0') { 375 if (s == NULL) { 376 *err_message = "binding before section"; 377 return EINVAL; 378 } 379 ret = parse_binding(f, lineno, p, &b, &s->u.list, err_message); 380 if (ret) 381 return ret; 382 } 383 } 384 return 0; 385 } 386 387 static int 388 is_plist_file(const char *fname) 389 { 390 size_t len = strlen(fname); 391 char suffix[] = ".plist"; 392 if (len < sizeof(suffix)) 393 return 0; 394 if (strcasecmp(&fname[len - (sizeof(suffix) - 1)], suffix) != 0) 395 return 0; 396 return 1; 397 } 398 399 /** 400 * Parse a configuration file and add the result into res. This 401 * interface can be used to parse several configuration files into one 402 * resulting krb5_config_section by calling it repeatably. 403 * 404 * @param context a Kerberos 5 context. 405 * @param fname a file name to a Kerberos configuration file 406 * @param res the returned result, must be free with krb5_free_config_files(). 407 * @return Return an error code or 0, see krb5_get_error_message(). 408 * 409 * @ingroup krb5_support 410 */ 411 412 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 413 krb5_config_parse_file_multi (krb5_context context, 414 const char *fname, 415 krb5_config_section **res) 416 { 417 const char *str; 418 char *newfname = NULL; 419 unsigned lineno = 0; 420 krb5_error_code ret; 421 struct fileptr f; 422 423 /** 424 * If the fname starts with "~/" parse configuration file in the 425 * current users home directory. The behavior can be disabled and 426 * enabled by calling krb5_set_home_dir_access(). 427 */ 428 if (fname[0] == '~' && fname[1] == '/') { 429 #ifndef KRB5_USE_PATH_TOKENS 430 const char *home = NULL; 431 432 if (!_krb5_homedir_access(context)) { 433 krb5_set_error_message(context, EPERM, 434 "Access to home directory not allowed"); 435 return EPERM; 436 } 437 438 if(!issuid()) 439 home = getenv("HOME"); 440 441 if (home == NULL) { 442 struct passwd *pw = getpwuid(getuid()); 443 if(pw != NULL) 444 home = pw->pw_dir; 445 } 446 if (home) { 447 asprintf(&newfname, "%s%s", home, &fname[1]); 448 if (newfname == NULL) { 449 krb5_set_error_message(context, ENOMEM, 450 N_("malloc: out of memory", "")); 451 return ENOMEM; 452 } 453 fname = newfname; 454 } 455 #else /* KRB5_USE_PATH_TOKENS */ 456 if (asprintf(&newfname, "%%{USERCONFIG}%s", &fname[1]) < 0 || 457 newfname == NULL) 458 { 459 krb5_set_error_message(context, ENOMEM, 460 N_("malloc: out of memory", "")); 461 return ENOMEM; 462 } 463 fname = newfname; 464 #endif 465 } 466 467 if (is_plist_file(fname)) { 468 #ifdef __APPLE__ 469 ret = parse_plist_config(context, fname, res); 470 if (ret) { 471 krb5_set_error_message(context, ret, 472 "Failed to parse plist %s", fname); 473 if (newfname) 474 free(newfname); 475 return ret; 476 } 477 #else 478 krb5_set_error_message(context, ENOENT, 479 "no support for plist configuration files"); 480 return ENOENT; 481 #endif 482 } else { 483 #ifdef KRB5_USE_PATH_TOKENS 484 char * exp_fname = NULL; 485 486 ret = _krb5_expand_path_tokens(context, fname, &exp_fname); 487 if (ret) { 488 if (newfname) 489 free(newfname); 490 return ret; 491 } 492 493 if (newfname) 494 free(newfname); 495 fname = newfname = exp_fname; 496 #endif 497 498 f.f = fopen(fname, "r"); 499 f.s = NULL; 500 if(f.f == NULL) { 501 ret = errno; 502 krb5_set_error_message (context, ret, "open %s: %s", 503 fname, strerror(ret)); 504 if (newfname) 505 free(newfname); 506 return ret; 507 } 508 509 ret = krb5_config_parse_debug (&f, res, &lineno, &str); 510 fclose(f.f); 511 if (ret) { 512 krb5_set_error_message (context, ret, "%s:%u: %s", 513 fname, lineno, str); 514 if (newfname) 515 free(newfname); 516 return ret; 517 } 518 } 519 return 0; 520 } 521 522 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 523 krb5_config_parse_file (krb5_context context, 524 const char *fname, 525 krb5_config_section **res) 526 { 527 *res = NULL; 528 return krb5_config_parse_file_multi(context, fname, res); 529 } 530 531 static void 532 free_binding (krb5_context context, krb5_config_binding *b) 533 { 534 krb5_config_binding *next_b; 535 536 while (b) { 537 free (b->name); 538 if (b->type == krb5_config_string) 539 free (b->u.string); 540 else if (b->type == krb5_config_list) 541 free_binding (context, b->u.list); 542 else 543 krb5_abortx(context, "unknown binding type (%d) in free_binding", 544 b->type); 545 next_b = b->next; 546 free (b); 547 b = next_b; 548 } 549 } 550 551 /** 552 * Free configuration file section, the result of 553 * krb5_config_parse_file() and krb5_config_parse_file_multi(). 554 * 555 * @param context A Kerberos 5 context 556 * @param s the configuration section to free 557 * 558 * @return returns 0 on successes, otherwise an error code, see 559 * krb5_get_error_message() 560 * 561 * @ingroup krb5_support 562 */ 563 564 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 565 krb5_config_file_free (krb5_context context, krb5_config_section *s) 566 { 567 free_binding (context, s); 568 return 0; 569 } 570 571 #ifndef HEIMDAL_SMALLER 572 573 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 574 _krb5_config_copy(krb5_context context, 575 krb5_config_section *c, 576 krb5_config_section **head) 577 { 578 krb5_config_binding *d, *previous = NULL; 579 580 *head = NULL; 581 582 while (c) { 583 d = calloc(1, sizeof(*d)); 584 585 if (*head == NULL) 586 *head = d; 587 588 d->name = strdup(c->name); 589 d->type = c->type; 590 if (d->type == krb5_config_string) 591 d->u.string = strdup(c->u.string); 592 else if (d->type == krb5_config_list) 593 _krb5_config_copy (context, c->u.list, &d->u.list); 594 else 595 krb5_abortx(context, 596 "unknown binding type (%d) in krb5_config_copy", 597 d->type); 598 if (previous) 599 previous->next = d; 600 601 previous = d; 602 c = c->next; 603 } 604 return 0; 605 } 606 607 #endif /* HEIMDAL_SMALLER */ 608 609 KRB5_LIB_FUNCTION const void * KRB5_LIB_CALL 610 _krb5_config_get_next (krb5_context context, 611 const krb5_config_section *c, 612 const krb5_config_binding **pointer, 613 int type, 614 ...) 615 { 616 const char *ret; 617 va_list args; 618 619 va_start(args, type); 620 ret = _krb5_config_vget_next (context, c, pointer, type, args); 621 va_end(args); 622 return ret; 623 } 624 625 static const void * 626 vget_next(krb5_context context, 627 const krb5_config_binding *b, 628 const krb5_config_binding **pointer, 629 int type, 630 const char *name, 631 va_list args) 632 { 633 const char *p = va_arg(args, const char *); 634 while(b != NULL) { 635 if(strcmp(b->name, name) == 0) { 636 if(b->type == (unsigned)type && p == NULL) { 637 *pointer = b; 638 return b->u.generic; 639 } else if(b->type == krb5_config_list && p != NULL) { 640 return vget_next(context, b->u.list, pointer, type, p, args); 641 } 642 } 643 b = b->next; 644 } 645 return NULL; 646 } 647 648 KRB5_LIB_FUNCTION const void * KRB5_LIB_CALL 649 _krb5_config_vget_next (krb5_context context, 650 const krb5_config_section *c, 651 const krb5_config_binding **pointer, 652 int type, 653 va_list args) 654 { 655 const krb5_config_binding *b; 656 const char *p; 657 658 if(c == NULL) 659 c = context->cf; 660 661 if (c == NULL) 662 return NULL; 663 664 if (*pointer == NULL) { 665 /* first time here, walk down the tree looking for the right 666 section */ 667 p = va_arg(args, const char *); 668 if (p == NULL) 669 return NULL; 670 return vget_next(context, c, pointer, type, p, args); 671 } 672 673 /* we were called again, so just look for more entries with the 674 same name and type */ 675 for (b = (*pointer)->next; b != NULL; b = b->next) { 676 if(strcmp(b->name, (*pointer)->name) == 0 && b->type == (unsigned)type) { 677 *pointer = b; 678 return b->u.generic; 679 } 680 } 681 return NULL; 682 } 683 684 KRB5_LIB_FUNCTION const void * KRB5_LIB_CALL 685 _krb5_config_get (krb5_context context, 686 const krb5_config_section *c, 687 int type, 688 ...) 689 { 690 const void *ret; 691 va_list args; 692 693 va_start(args, type); 694 ret = _krb5_config_vget (context, c, type, args); 695 va_end(args); 696 return ret; 697 } 698 699 700 const void * 701 _krb5_config_vget (krb5_context context, 702 const krb5_config_section *c, 703 int type, 704 va_list args) 705 { 706 const krb5_config_binding *foo = NULL; 707 708 return _krb5_config_vget_next (context, c, &foo, type, args); 709 } 710 711 /** 712 * Get a list of configuration binding list for more processing 713 * 714 * @param context A Kerberos 5 context. 715 * @param c a configuration section, or NULL to use the section from context 716 * @param ... a list of names, terminated with NULL. 717 * 718 * @return NULL if configuration list is not found, a list otherwise 719 * 720 * @ingroup krb5_support 721 */ 722 723 KRB5_LIB_FUNCTION const krb5_config_binding * KRB5_LIB_CALL 724 krb5_config_get_list (krb5_context context, 725 const krb5_config_section *c, 726 ...) 727 { 728 const krb5_config_binding *ret; 729 va_list args; 730 731 va_start(args, c); 732 ret = krb5_config_vget_list (context, c, args); 733 va_end(args); 734 return ret; 735 } 736 737 /** 738 * Get a list of configuration binding list for more processing 739 * 740 * @param context A Kerberos 5 context. 741 * @param c a configuration section, or NULL to use the section from context 742 * @param args a va_list of arguments 743 * 744 * @return NULL if configuration list is not found, a list otherwise 745 * 746 * @ingroup krb5_support 747 */ 748 749 KRB5_LIB_FUNCTION const krb5_config_binding * KRB5_LIB_CALL 750 krb5_config_vget_list (krb5_context context, 751 const krb5_config_section *c, 752 va_list args) 753 { 754 return _krb5_config_vget (context, c, krb5_config_list, args); 755 } 756 757 /** 758 * Returns a "const char *" to a string in the configuration database. 759 * The string may not be valid after a reload of the configuration 760 * database so a caller should make a local copy if it needs to keep 761 * the string. 762 * 763 * @param context A Kerberos 5 context. 764 * @param c a configuration section, or NULL to use the section from context 765 * @param ... a list of names, terminated with NULL. 766 * 767 * @return NULL if configuration string not found, a string otherwise 768 * 769 * @ingroup krb5_support 770 */ 771 772 KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL 773 krb5_config_get_string (krb5_context context, 774 const krb5_config_section *c, 775 ...) 776 { 777 const char *ret; 778 va_list args; 779 780 va_start(args, c); 781 ret = krb5_config_vget_string (context, c, args); 782 va_end(args); 783 return ret; 784 } 785 786 /** 787 * Like krb5_config_get_string(), but uses a va_list instead of ... 788 * 789 * @param context A Kerberos 5 context. 790 * @param c a configuration section, or NULL to use the section from context 791 * @param args a va_list of arguments 792 * 793 * @return NULL if configuration string not found, a string otherwise 794 * 795 * @ingroup krb5_support 796 */ 797 798 KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL 799 krb5_config_vget_string (krb5_context context, 800 const krb5_config_section *c, 801 va_list args) 802 { 803 return _krb5_config_vget (context, c, krb5_config_string, args); 804 } 805 806 /** 807 * Like krb5_config_vget_string(), but instead of returning NULL, 808 * instead return a default value. 809 * 810 * @param context A Kerberos 5 context. 811 * @param c a configuration section, or NULL to use the section from context 812 * @param def_value the default value to return if no configuration 813 * found in the database. 814 * @param args a va_list of arguments 815 * 816 * @return a configuration string 817 * 818 * @ingroup krb5_support 819 */ 820 821 KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL 822 krb5_config_vget_string_default (krb5_context context, 823 const krb5_config_section *c, 824 const char *def_value, 825 va_list args) 826 { 827 const char *ret; 828 829 ret = krb5_config_vget_string (context, c, args); 830 if (ret == NULL) 831 ret = def_value; 832 return ret; 833 } 834 835 /** 836 * Like krb5_config_get_string(), but instead of returning NULL, 837 * instead return a default value. 838 * 839 * @param context A Kerberos 5 context. 840 * @param c a configuration section, or NULL to use the section from context 841 * @param def_value the default value to return if no configuration 842 * found in the database. 843 * @param ... a list of names, terminated with NULL. 844 * 845 * @return a configuration string 846 * 847 * @ingroup krb5_support 848 */ 849 850 KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL 851 krb5_config_get_string_default (krb5_context context, 852 const krb5_config_section *c, 853 const char *def_value, 854 ...) 855 { 856 const char *ret; 857 va_list args; 858 859 va_start(args, def_value); 860 ret = krb5_config_vget_string_default (context, c, def_value, args); 861 va_end(args); 862 return ret; 863 } 864 865 static char * 866 next_component_string(char * begin, const char * delims, char **state) 867 { 868 char * end; 869 870 if (begin == NULL) 871 begin = *state; 872 873 if (*begin == '\0') 874 return NULL; 875 876 end = begin; 877 while (*end == '"') { 878 char * t = strchr(end + 1, '"'); 879 880 if (t) 881 end = ++t; 882 else 883 end += strlen(end); 884 } 885 886 if (*end != '\0') { 887 size_t pos; 888 889 pos = strcspn(end, delims); 890 end = end + pos; 891 } 892 893 if (*end != '\0') { 894 *end = '\0'; 895 *state = end + 1; 896 if (*begin == '"' && *(end - 1) == '"' && begin + 1 < end) { 897 begin++; *(end - 1) = '\0'; 898 } 899 return begin; 900 } 901 902 *state = end; 903 if (*begin == '"' && *(end - 1) == '"' && begin + 1 < end) { 904 begin++; *(end - 1) = '\0'; 905 } 906 return begin; 907 } 908 909 /** 910 * Get a list of configuration strings, free the result with 911 * krb5_config_free_strings(). 912 * 913 * @param context A Kerberos 5 context. 914 * @param c a configuration section, or NULL to use the section from context 915 * @param args a va_list of arguments 916 * 917 * @return TRUE or FALSE 918 * 919 * @ingroup krb5_support 920 */ 921 922 KRB5_LIB_FUNCTION char ** KRB5_LIB_CALL 923 krb5_config_vget_strings(krb5_context context, 924 const krb5_config_section *c, 925 va_list args) 926 { 927 char **strings = NULL; 928 int nstr = 0; 929 const krb5_config_binding *b = NULL; 930 const char *p; 931 932 while((p = _krb5_config_vget_next(context, c, &b, 933 krb5_config_string, args))) { 934 char *tmp = strdup(p); 935 char *pos = NULL; 936 char *s; 937 if(tmp == NULL) 938 goto cleanup; 939 s = next_component_string(tmp, " \t", &pos); 940 while(s){ 941 char **tmp2 = realloc(strings, (nstr + 1) * sizeof(*strings)); 942 if(tmp2 == NULL) 943 goto cleanup; 944 strings = tmp2; 945 strings[nstr] = strdup(s); 946 nstr++; 947 if(strings[nstr-1] == NULL) 948 goto cleanup; 949 s = next_component_string(NULL, " \t", &pos); 950 } 951 free(tmp); 952 } 953 if(nstr){ 954 char **tmp = realloc(strings, (nstr + 1) * sizeof(*strings)); 955 if(tmp == NULL) 956 goto cleanup; 957 strings = tmp; 958 strings[nstr] = NULL; 959 } 960 return strings; 961 cleanup: 962 while(nstr--) 963 free(strings[nstr]); 964 free(strings); 965 return NULL; 966 967 } 968 969 /** 970 * Get a list of configuration strings, free the result with 971 * krb5_config_free_strings(). 972 * 973 * @param context A Kerberos 5 context. 974 * @param c a configuration section, or NULL to use the section from context 975 * @param ... a list of names, terminated with NULL. 976 * 977 * @return TRUE or FALSE 978 * 979 * @ingroup krb5_support 980 */ 981 982 KRB5_LIB_FUNCTION char** KRB5_LIB_CALL 983 krb5_config_get_strings(krb5_context context, 984 const krb5_config_section *c, 985 ...) 986 { 987 va_list ap; 988 char **ret; 989 va_start(ap, c); 990 ret = krb5_config_vget_strings(context, c, ap); 991 va_end(ap); 992 return ret; 993 } 994 995 /** 996 * Free the resulting strings from krb5_config-get_strings() and 997 * krb5_config_vget_strings(). 998 * 999 * @param strings strings to free 1000 * 1001 * @ingroup krb5_support 1002 */ 1003 1004 KRB5_LIB_FUNCTION void KRB5_LIB_CALL 1005 krb5_config_free_strings(char **strings) 1006 { 1007 char **s = strings; 1008 while(s && *s){ 1009 free(*s); 1010 s++; 1011 } 1012 free(strings); 1013 } 1014 1015 /** 1016 * Like krb5_config_get_bool_default() but with a va_list list of 1017 * configuration selection. 1018 * 1019 * Configuration value to a boolean value, where yes/true and any 1020 * non-zero number means TRUE and other value is FALSE. 1021 * 1022 * @param context A Kerberos 5 context. 1023 * @param c a configuration section, or NULL to use the section from context 1024 * @param def_value the default value to return if no configuration 1025 * found in the database. 1026 * @param args a va_list of arguments 1027 * 1028 * @return TRUE or FALSE 1029 * 1030 * @ingroup krb5_support 1031 */ 1032 1033 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 1034 krb5_config_vget_bool_default (krb5_context context, 1035 const krb5_config_section *c, 1036 krb5_boolean def_value, 1037 va_list args) 1038 { 1039 const char *str; 1040 str = krb5_config_vget_string (context, c, args); 1041 if(str == NULL) 1042 return def_value; 1043 if(strcasecmp(str, "yes") == 0 || 1044 strcasecmp(str, "true") == 0 || 1045 atoi(str)) return TRUE; 1046 return FALSE; 1047 } 1048 1049 /** 1050 * krb5_config_get_bool() will convert the configuration 1051 * option value to a boolean value, where yes/true and any non-zero 1052 * number means TRUE and other value is FALSE. 1053 * 1054 * @param context A Kerberos 5 context. 1055 * @param c a configuration section, or NULL to use the section from context 1056 * @param args a va_list of arguments 1057 * 1058 * @return TRUE or FALSE 1059 * 1060 * @ingroup krb5_support 1061 */ 1062 1063 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 1064 krb5_config_vget_bool (krb5_context context, 1065 const krb5_config_section *c, 1066 va_list args) 1067 { 1068 return krb5_config_vget_bool_default (context, c, FALSE, args); 1069 } 1070 1071 /** 1072 * krb5_config_get_bool_default() will convert the configuration 1073 * option value to a boolean value, where yes/true and any non-zero 1074 * number means TRUE and other value is FALSE. 1075 * 1076 * @param context A Kerberos 5 context. 1077 * @param c a configuration section, or NULL to use the section from context 1078 * @param def_value the default value to return if no configuration 1079 * found in the database. 1080 * @param ... a list of names, terminated with NULL. 1081 * 1082 * @return TRUE or FALSE 1083 * 1084 * @ingroup krb5_support 1085 */ 1086 1087 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 1088 krb5_config_get_bool_default (krb5_context context, 1089 const krb5_config_section *c, 1090 krb5_boolean def_value, 1091 ...) 1092 { 1093 va_list ap; 1094 krb5_boolean ret; 1095 va_start(ap, def_value); 1096 ret = krb5_config_vget_bool_default(context, c, def_value, ap); 1097 va_end(ap); 1098 return ret; 1099 } 1100 1101 /** 1102 * Like krb5_config_get_bool() but with a va_list list of 1103 * configuration selection. 1104 * 1105 * Configuration value to a boolean value, where yes/true and any 1106 * non-zero number means TRUE and other value is FALSE. 1107 * 1108 * @param context A Kerberos 5 context. 1109 * @param c a configuration section, or NULL to use the section from context 1110 * @param ... a list of names, terminated with NULL. 1111 * 1112 * @return TRUE or FALSE 1113 * 1114 * @ingroup krb5_support 1115 */ 1116 1117 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 1118 krb5_config_get_bool (krb5_context context, 1119 const krb5_config_section *c, 1120 ...) 1121 { 1122 va_list ap; 1123 krb5_boolean ret; 1124 va_start(ap, c); 1125 ret = krb5_config_vget_bool (context, c, ap); 1126 va_end(ap); 1127 return ret; 1128 } 1129 1130 /** 1131 * Get the time from the configuration file using a relative time. 1132 * 1133 * Like krb5_config_get_time_default() but with a va_list list of 1134 * configuration selection. 1135 * 1136 * @param context A Kerberos 5 context. 1137 * @param c a configuration section, or NULL to use the section from context 1138 * @param def_value the default value to return if no configuration 1139 * found in the database. 1140 * @param args a va_list of arguments 1141 * 1142 * @return parsed the time (or def_value on parse error) 1143 * 1144 * @ingroup krb5_support 1145 */ 1146 1147 KRB5_LIB_FUNCTION int KRB5_LIB_CALL 1148 krb5_config_vget_time_default (krb5_context context, 1149 const krb5_config_section *c, 1150 int def_value, 1151 va_list args) 1152 { 1153 const char *str; 1154 krb5_deltat t; 1155 1156 str = krb5_config_vget_string (context, c, args); 1157 if(str == NULL) 1158 return def_value; 1159 if (krb5_string_to_deltat(str, &t)) 1160 return def_value; 1161 return t; 1162 } 1163 1164 /** 1165 * Get the time from the configuration file using a relative time, for example: 1h30s 1166 * 1167 * @param context A Kerberos 5 context. 1168 * @param c a configuration section, or NULL to use the section from context 1169 * @param args a va_list of arguments 1170 * 1171 * @return parsed the time or -1 on error 1172 * 1173 * @ingroup krb5_support 1174 */ 1175 1176 KRB5_LIB_FUNCTION int KRB5_LIB_CALL 1177 krb5_config_vget_time (krb5_context context, 1178 const krb5_config_section *c, 1179 va_list args) 1180 { 1181 return krb5_config_vget_time_default (context, c, -1, args); 1182 } 1183 1184 /** 1185 * Get the time from the configuration file using a relative time, for example: 1h30s 1186 * 1187 * @param context A Kerberos 5 context. 1188 * @param c a configuration section, or NULL to use the section from context 1189 * @param def_value the default value to return if no configuration 1190 * found in the database. 1191 * @param ... a list of names, terminated with NULL. 1192 * 1193 * @return parsed the time (or def_value on parse error) 1194 * 1195 * @ingroup krb5_support 1196 */ 1197 1198 KRB5_LIB_FUNCTION int KRB5_LIB_CALL 1199 krb5_config_get_time_default (krb5_context context, 1200 const krb5_config_section *c, 1201 int def_value, 1202 ...) 1203 { 1204 va_list ap; 1205 int ret; 1206 va_start(ap, def_value); 1207 ret = krb5_config_vget_time_default(context, c, def_value, ap); 1208 va_end(ap); 1209 return ret; 1210 } 1211 1212 /** 1213 * Get the time from the configuration file using a relative time, for example: 1h30s 1214 * 1215 * @param context A Kerberos 5 context. 1216 * @param c a configuration section, or NULL to use the section from context 1217 * @param ... a list of names, terminated with NULL. 1218 * 1219 * @return parsed the time or -1 on error 1220 * 1221 * @ingroup krb5_support 1222 */ 1223 1224 KRB5_LIB_FUNCTION int KRB5_LIB_CALL 1225 krb5_config_get_time (krb5_context context, 1226 const krb5_config_section *c, 1227 ...) 1228 { 1229 va_list ap; 1230 int ret; 1231 va_start(ap, c); 1232 ret = krb5_config_vget_time (context, c, ap); 1233 va_end(ap); 1234 return ret; 1235 } 1236 1237 1238 KRB5_LIB_FUNCTION int KRB5_LIB_CALL 1239 krb5_config_vget_int_default (krb5_context context, 1240 const krb5_config_section *c, 1241 int def_value, 1242 va_list args) 1243 { 1244 const char *str; 1245 str = krb5_config_vget_string (context, c, args); 1246 if(str == NULL) 1247 return def_value; 1248 else { 1249 char *endptr; 1250 long l; 1251 l = strtol(str, &endptr, 0); 1252 if (endptr == str) 1253 return def_value; 1254 else 1255 return l; 1256 } 1257 } 1258 1259 KRB5_LIB_FUNCTION int KRB5_LIB_CALL 1260 krb5_config_vget_int (krb5_context context, 1261 const krb5_config_section *c, 1262 va_list args) 1263 { 1264 return krb5_config_vget_int_default (context, c, -1, args); 1265 } 1266 1267 KRB5_LIB_FUNCTION int KRB5_LIB_CALL 1268 krb5_config_get_int_default (krb5_context context, 1269 const krb5_config_section *c, 1270 int def_value, 1271 ...) 1272 { 1273 va_list ap; 1274 int ret; 1275 va_start(ap, def_value); 1276 ret = krb5_config_vget_int_default(context, c, def_value, ap); 1277 va_end(ap); 1278 return ret; 1279 } 1280 1281 KRB5_LIB_FUNCTION int KRB5_LIB_CALL 1282 krb5_config_get_int (krb5_context context, 1283 const krb5_config_section *c, 1284 ...) 1285 { 1286 va_list ap; 1287 int ret; 1288 va_start(ap, c); 1289 ret = krb5_config_vget_int (context, c, ap); 1290 va_end(ap); 1291 return ret; 1292 } 1293 1294 1295 #ifndef HEIMDAL_SMALLER 1296 1297 /** 1298 * Deprecated: configuration files are not strings 1299 * 1300 * @ingroup krb5_deprecated 1301 */ 1302 1303 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1304 krb5_config_parse_string_multi(krb5_context context, 1305 const char *string, 1306 krb5_config_section **res) 1307 KRB5_DEPRECATED_FUNCTION("Use X instead") 1308 { 1309 const char *str; 1310 unsigned lineno = 0; 1311 krb5_error_code ret; 1312 struct fileptr f; 1313 f.f = NULL; 1314 f.s = string; 1315 1316 ret = krb5_config_parse_debug (&f, res, &lineno, &str); 1317 if (ret) { 1318 krb5_set_error_message (context, ret, "%s:%u: %s", 1319 "<constant>", lineno, str); 1320 return ret; 1321 } 1322 return 0; 1323 } 1324 1325 #endif 1326