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