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