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