1 /* 2 * Copyright (c) 1997 - 2004 Kungliga Tekniska H�gskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include "krb5_locl.h" 35 RCSID("$Id: config_file.c 19213 2006-12-04 23:36:36Z lha $"); 36 37 #ifndef HAVE_NETINFO 38 39 /* Gaah! I want a portable funopen */ 40 struct fileptr { 41 const char *s; 42 FILE *f; 43 }; 44 45 static char * 46 config_fgets(char *str, size_t len, struct fileptr *ptr) 47 { 48 /* XXX this is not correct, in that they don't do the same if the 49 line is longer than len */ 50 if(ptr->f != NULL) 51 return fgets(str, len, ptr->f); 52 else { 53 /* this is almost strsep_copy */ 54 const char *p; 55 ssize_t l; 56 if(*ptr->s == '\0') 57 return NULL; 58 p = ptr->s + strcspn(ptr->s, "\n"); 59 if(*p == '\n') 60 p++; 61 l = min(len, p - ptr->s); 62 if(len > 0) { 63 memcpy(str, ptr->s, l); 64 str[l] = '\0'; 65 } 66 ptr->s = p; 67 return str; 68 } 69 } 70 71 static krb5_error_code parse_section(char *p, krb5_config_section **s, 72 krb5_config_section **res, 73 const char **error_message); 74 static krb5_error_code parse_binding(struct fileptr *f, unsigned *lineno, char *p, 75 krb5_config_binding **b, 76 krb5_config_binding **parent, 77 const char **error_message); 78 static krb5_error_code parse_list(struct fileptr *f, unsigned *lineno, 79 krb5_config_binding **parent, 80 const char **error_message); 81 82 static krb5_config_section * 83 get_entry(krb5_config_section **parent, const char *name, int type) 84 { 85 krb5_config_section **q; 86 87 for(q = parent; *q != NULL; q = &(*q)->next) 88 if(type == krb5_config_list && 89 type == (*q)->type && 90 strcmp(name, (*q)->name) == 0) 91 return *q; 92 *q = calloc(1, sizeof(**q)); 93 if(*q == NULL) 94 return NULL; 95 (*q)->name = strdup(name); 96 (*q)->type = type; 97 if((*q)->name == NULL) { 98 free(*q); 99 *q = NULL; 100 return NULL; 101 } 102 return *q; 103 } 104 105 /* 106 * Parse a section: 107 * 108 * [section] 109 * foo = bar 110 * b = { 111 * a 112 * } 113 * ... 114 * 115 * starting at the line in `p', storing the resulting structure in 116 * `s' and hooking it into `parent'. 117 * Store the error message in `error_message'. 118 */ 119 120 static krb5_error_code 121 parse_section(char *p, krb5_config_section **s, krb5_config_section **parent, 122 const char **error_message) 123 { 124 char *p1; 125 krb5_config_section *tmp; 126 127 p1 = strchr (p + 1, ']'); 128 if (p1 == NULL) { 129 *error_message = "missing ]"; 130 return KRB5_CONFIG_BADFORMAT; 131 } 132 *p1 = '\0'; 133 tmp = get_entry(parent, p + 1, krb5_config_list); 134 if(tmp == NULL) { 135 *error_message = "out of memory"; 136 return KRB5_CONFIG_BADFORMAT; 137 } 138 *s = tmp; 139 return 0; 140 } 141 142 /* 143 * Parse a brace-enclosed list from `f', hooking in the structure at 144 * `parent'. 145 * Store the error message in `error_message'. 146 */ 147 148 static krb5_error_code 149 parse_list(struct fileptr *f, unsigned *lineno, krb5_config_binding **parent, 150 const char **error_message) 151 { 152 char buf[BUFSIZ]; 153 krb5_error_code ret; 154 krb5_config_binding *b = NULL; 155 unsigned beg_lineno = *lineno; 156 157 while(config_fgets(buf, sizeof(buf), f) != NULL) { 158 char *p; 159 160 ++*lineno; 161 buf[strcspn(buf, "\r\n")] = '\0'; 162 p = buf; 163 while(isspace((unsigned char)*p)) 164 ++p; 165 if (*p == '#' || *p == ';' || *p == '\0') 166 continue; 167 while(isspace((unsigned char)*p)) 168 ++p; 169 if (*p == '}') 170 return 0; 171 if (*p == '\0') 172 continue; 173 ret = parse_binding (f, lineno, p, &b, parent, error_message); 174 if (ret) 175 return ret; 176 } 177 *lineno = beg_lineno; 178 *error_message = "unclosed {"; 179 return KRB5_CONFIG_BADFORMAT; 180 } 181 182 /* 183 * 184 */ 185 186 static krb5_error_code 187 parse_binding(struct fileptr *f, unsigned *lineno, char *p, 188 krb5_config_binding **b, krb5_config_binding **parent, 189 const char **error_message) 190 { 191 krb5_config_binding *tmp; 192 char *p1, *p2; 193 krb5_error_code ret = 0; 194 195 p1 = p; 196 while (*p && *p != '=' && !isspace((unsigned char)*p)) 197 ++p; 198 if (*p == '\0') { 199 *error_message = "missing ="; 200 return KRB5_CONFIG_BADFORMAT; 201 } 202 p2 = p; 203 while (isspace((unsigned char)*p)) 204 ++p; 205 if (*p != '=') { 206 *error_message = "missing ="; 207 return KRB5_CONFIG_BADFORMAT; 208 } 209 ++p; 210 while(isspace((unsigned char)*p)) 211 ++p; 212 *p2 = '\0'; 213 if (*p == '{') { 214 tmp = get_entry(parent, p1, krb5_config_list); 215 if (tmp == NULL) { 216 *error_message = "out of memory"; 217 return KRB5_CONFIG_BADFORMAT; 218 } 219 ret = parse_list (f, lineno, &tmp->u.list, error_message); 220 } else { 221 tmp = get_entry(parent, p1, krb5_config_string); 222 if (tmp == NULL) { 223 *error_message = "out of memory"; 224 return KRB5_CONFIG_BADFORMAT; 225 } 226 p1 = p; 227 p = p1 + strlen(p1); 228 while(p > p1 && isspace((unsigned char)*(p-1))) 229 --p; 230 *p = '\0'; 231 tmp->u.string = strdup(p1); 232 } 233 *b = tmp; 234 return ret; 235 } 236 237 /* 238 * Parse the config file `fname', generating the structures into `res' 239 * returning error messages in `error_message' 240 */ 241 242 static krb5_error_code 243 krb5_config_parse_debug (struct fileptr *f, 244 krb5_config_section **res, 245 unsigned *lineno, 246 const char **error_message) 247 { 248 krb5_config_section *s = NULL; 249 krb5_config_binding *b = NULL; 250 char buf[BUFSIZ]; 251 krb5_error_code ret; 252 253 while (config_fgets(buf, sizeof(buf), f) != NULL) { 254 char *p; 255 256 ++*lineno; 257 buf[strcspn(buf, "\r\n")] = '\0'; 258 p = buf; 259 while(isspace((unsigned char)*p)) 260 ++p; 261 if (*p == '#' || *p == ';') 262 continue; 263 if (*p == '[') { 264 ret = parse_section(p, &s, res, error_message); 265 if (ret) 266 return ret; 267 b = NULL; 268 } else if (*p == '}') { 269 *error_message = "unmatched }"; 270 return EINVAL; /* XXX */ 271 } else if(*p != '\0') { 272 if (s == NULL) { 273 *error_message = "binding before section"; 274 return EINVAL; 275 } 276 ret = parse_binding(f, lineno, p, &b, &s->u.list, error_message); 277 if (ret) 278 return ret; 279 } 280 } 281 return 0; 282 } 283 284 krb5_error_code KRB5_LIB_FUNCTION 285 krb5_config_parse_string_multi(krb5_context context, 286 const char *string, 287 krb5_config_section **res) 288 { 289 const char *str; 290 unsigned lineno = 0; 291 krb5_error_code ret; 292 struct fileptr f; 293 f.f = NULL; 294 f.s = string; 295 296 ret = krb5_config_parse_debug (&f, res, &lineno, &str); 297 if (ret) { 298 krb5_set_error_string (context, "%s:%u: %s", "<constant>", lineno, str); 299 return ret; 300 } 301 return 0; 302 } 303 304 krb5_error_code KRB5_LIB_FUNCTION 305 krb5_config_parse_file_multi (krb5_context context, 306 const char *fname, 307 krb5_config_section **res) 308 { 309 const char *str; 310 unsigned lineno = 0; 311 krb5_error_code ret; 312 struct fileptr f; 313 f.f = fopen(fname, "r"); 314 f.s = NULL; 315 if(f.f == NULL) { 316 ret = errno; 317 krb5_set_error_string (context, "open %s: %s", fname, strerror(ret)); 318 return ret; 319 } 320 321 ret = krb5_config_parse_debug (&f, res, &lineno, &str); 322 fclose(f.f); 323 if (ret) { 324 krb5_set_error_string (context, "%s:%u: %s", fname, lineno, str); 325 return ret; 326 } 327 return 0; 328 } 329 330 krb5_error_code KRB5_LIB_FUNCTION 331 krb5_config_parse_file (krb5_context context, 332 const char *fname, 333 krb5_config_section **res) 334 { 335 *res = NULL; 336 return krb5_config_parse_file_multi(context, fname, res); 337 } 338 339 #endif /* !HAVE_NETINFO */ 340 341 static void 342 free_binding (krb5_context context, krb5_config_binding *b) 343 { 344 krb5_config_binding *next_b; 345 346 while (b) { 347 free (b->name); 348 if (b->type == krb5_config_string) 349 free (b->u.string); 350 else if (b->type == krb5_config_list) 351 free_binding (context, b->u.list); 352 else 353 krb5_abortx(context, "unknown binding type (%d) in free_binding", 354 b->type); 355 next_b = b->next; 356 free (b); 357 b = next_b; 358 } 359 } 360 361 krb5_error_code KRB5_LIB_FUNCTION 362 krb5_config_file_free (krb5_context context, krb5_config_section *s) 363 { 364 free_binding (context, s); 365 return 0; 366 } 367 368 const void * 369 krb5_config_get_next (krb5_context context, 370 const krb5_config_section *c, 371 const krb5_config_binding **pointer, 372 int type, 373 ...) 374 { 375 const char *ret; 376 va_list args; 377 378 va_start(args, type); 379 ret = krb5_config_vget_next (context, c, pointer, type, args); 380 va_end(args); 381 return ret; 382 } 383 384 static const void * 385 vget_next(krb5_context context, 386 const krb5_config_binding *b, 387 const krb5_config_binding **pointer, 388 int type, 389 const char *name, 390 va_list args) 391 { 392 const char *p = va_arg(args, const char *); 393 while(b != NULL) { 394 if(strcmp(b->name, name) == 0) { 395 if(b->type == type && p == NULL) { 396 *pointer = b; 397 return b->u.generic; 398 } else if(b->type == krb5_config_list && p != NULL) { 399 return vget_next(context, b->u.list, pointer, type, p, args); 400 } 401 } 402 b = b->next; 403 } 404 return NULL; 405 } 406 407 const void * 408 krb5_config_vget_next (krb5_context context, 409 const krb5_config_section *c, 410 const krb5_config_binding **pointer, 411 int type, 412 va_list args) 413 { 414 const krb5_config_binding *b; 415 const char *p; 416 417 if(c == NULL) 418 c = context->cf; 419 420 if (c == NULL) 421 return NULL; 422 423 if (*pointer == NULL) { 424 /* first time here, walk down the tree looking for the right 425 section */ 426 p = va_arg(args, const char *); 427 if (p == NULL) 428 return NULL; 429 return vget_next(context, c, pointer, type, p, args); 430 } 431 432 /* we were called again, so just look for more entries with the 433 same name and type */ 434 for (b = (*pointer)->next; b != NULL; b = b->next) { 435 if(strcmp(b->name, (*pointer)->name) == 0 && b->type == type) { 436 *pointer = b; 437 return b->u.generic; 438 } 439 } 440 return NULL; 441 } 442 443 const void * 444 krb5_config_get (krb5_context context, 445 const krb5_config_section *c, 446 int type, 447 ...) 448 { 449 const void *ret; 450 va_list args; 451 452 va_start(args, type); 453 ret = krb5_config_vget (context, c, type, args); 454 va_end(args); 455 return ret; 456 } 457 458 const void * 459 krb5_config_vget (krb5_context context, 460 const krb5_config_section *c, 461 int type, 462 va_list args) 463 { 464 const krb5_config_binding *foo = NULL; 465 466 return krb5_config_vget_next (context, c, &foo, type, args); 467 } 468 469 const krb5_config_binding * 470 krb5_config_get_list (krb5_context context, 471 const krb5_config_section *c, 472 ...) 473 { 474 const krb5_config_binding *ret; 475 va_list args; 476 477 va_start(args, c); 478 ret = krb5_config_vget_list (context, c, args); 479 va_end(args); 480 return ret; 481 } 482 483 const krb5_config_binding * 484 krb5_config_vget_list (krb5_context context, 485 const krb5_config_section *c, 486 va_list args) 487 { 488 return krb5_config_vget (context, c, krb5_config_list, args); 489 } 490 491 const char* KRB5_LIB_FUNCTION 492 krb5_config_get_string (krb5_context context, 493 const krb5_config_section *c, 494 ...) 495 { 496 const char *ret; 497 va_list args; 498 499 va_start(args, c); 500 ret = krb5_config_vget_string (context, c, args); 501 va_end(args); 502 return ret; 503 } 504 505 const char* KRB5_LIB_FUNCTION 506 krb5_config_vget_string (krb5_context context, 507 const krb5_config_section *c, 508 va_list args) 509 { 510 return krb5_config_vget (context, c, krb5_config_string, args); 511 } 512 513 const char* KRB5_LIB_FUNCTION 514 krb5_config_vget_string_default (krb5_context context, 515 const krb5_config_section *c, 516 const char *def_value, 517 va_list args) 518 { 519 const char *ret; 520 521 ret = krb5_config_vget_string (context, c, args); 522 if (ret == NULL) 523 ret = def_value; 524 return ret; 525 } 526 527 const char* KRB5_LIB_FUNCTION 528 krb5_config_get_string_default (krb5_context context, 529 const krb5_config_section *c, 530 const char *def_value, 531 ...) 532 { 533 const char *ret; 534 va_list args; 535 536 va_start(args, def_value); 537 ret = krb5_config_vget_string_default (context, c, def_value, args); 538 va_end(args); 539 return ret; 540 } 541 542 char ** KRB5_LIB_FUNCTION 543 krb5_config_vget_strings(krb5_context context, 544 const krb5_config_section *c, 545 va_list args) 546 { 547 char **strings = NULL; 548 int nstr = 0; 549 const krb5_config_binding *b = NULL; 550 const char *p; 551 552 while((p = krb5_config_vget_next(context, c, &b, 553 krb5_config_string, args))) { 554 char *tmp = strdup(p); 555 char *pos = NULL; 556 char *s; 557 if(tmp == NULL) 558 goto cleanup; 559 s = strtok_r(tmp, " \t", &pos); 560 while(s){ 561 char **tmp2 = realloc(strings, (nstr + 1) * sizeof(*strings)); 562 if(tmp2 == NULL) 563 goto cleanup; 564 strings = tmp2; 565 strings[nstr] = strdup(s); 566 nstr++; 567 if(strings[nstr-1] == NULL) 568 goto cleanup; 569 s = strtok_r(NULL, " \t", &pos); 570 } 571 free(tmp); 572 } 573 if(nstr){ 574 char **tmp = realloc(strings, (nstr + 1) * sizeof(*strings)); 575 if(tmp == NULL) 576 goto cleanup; 577 strings = tmp; 578 strings[nstr] = NULL; 579 } 580 return strings; 581 cleanup: 582 while(nstr--) 583 free(strings[nstr]); 584 free(strings); 585 return NULL; 586 587 } 588 589 char** 590 krb5_config_get_strings(krb5_context context, 591 const krb5_config_section *c, 592 ...) 593 { 594 va_list ap; 595 char **ret; 596 va_start(ap, c); 597 ret = krb5_config_vget_strings(context, c, ap); 598 va_end(ap); 599 return ret; 600 } 601 602 void KRB5_LIB_FUNCTION 603 krb5_config_free_strings(char **strings) 604 { 605 char **s = strings; 606 while(s && *s){ 607 free(*s); 608 s++; 609 } 610 free(strings); 611 } 612 613 krb5_boolean KRB5_LIB_FUNCTION 614 krb5_config_vget_bool_default (krb5_context context, 615 const krb5_config_section *c, 616 krb5_boolean def_value, 617 va_list args) 618 { 619 const char *str; 620 str = krb5_config_vget_string (context, c, args); 621 if(str == NULL) 622 return def_value; 623 if(strcasecmp(str, "yes") == 0 || 624 strcasecmp(str, "true") == 0 || 625 atoi(str)) return TRUE; 626 return FALSE; 627 } 628 629 krb5_boolean KRB5_LIB_FUNCTION 630 krb5_config_vget_bool (krb5_context context, 631 const krb5_config_section *c, 632 va_list args) 633 { 634 return krb5_config_vget_bool_default (context, c, FALSE, args); 635 } 636 637 krb5_boolean KRB5_LIB_FUNCTION 638 krb5_config_get_bool_default (krb5_context context, 639 const krb5_config_section *c, 640 krb5_boolean def_value, 641 ...) 642 { 643 va_list ap; 644 krb5_boolean ret; 645 va_start(ap, def_value); 646 ret = krb5_config_vget_bool_default(context, c, def_value, ap); 647 va_end(ap); 648 return ret; 649 } 650 651 krb5_boolean KRB5_LIB_FUNCTION 652 krb5_config_get_bool (krb5_context context, 653 const krb5_config_section *c, 654 ...) 655 { 656 va_list ap; 657 krb5_boolean ret; 658 va_start(ap, c); 659 ret = krb5_config_vget_bool (context, c, ap); 660 va_end(ap); 661 return ret; 662 } 663 664 int KRB5_LIB_FUNCTION 665 krb5_config_vget_time_default (krb5_context context, 666 const krb5_config_section *c, 667 int def_value, 668 va_list args) 669 { 670 const char *str; 671 krb5_deltat t; 672 673 str = krb5_config_vget_string (context, c, args); 674 if(str == NULL) 675 return def_value; 676 if (krb5_string_to_deltat(str, &t)) 677 return def_value; 678 return t; 679 } 680 681 int KRB5_LIB_FUNCTION 682 krb5_config_vget_time (krb5_context context, 683 const krb5_config_section *c, 684 va_list args) 685 { 686 return krb5_config_vget_time_default (context, c, -1, args); 687 } 688 689 int KRB5_LIB_FUNCTION 690 krb5_config_get_time_default (krb5_context context, 691 const krb5_config_section *c, 692 int def_value, 693 ...) 694 { 695 va_list ap; 696 int ret; 697 va_start(ap, def_value); 698 ret = krb5_config_vget_time_default(context, c, def_value, ap); 699 va_end(ap); 700 return ret; 701 } 702 703 int KRB5_LIB_FUNCTION 704 krb5_config_get_time (krb5_context context, 705 const krb5_config_section *c, 706 ...) 707 { 708 va_list ap; 709 int ret; 710 va_start(ap, c); 711 ret = krb5_config_vget_time (context, c, ap); 712 va_end(ap); 713 return ret; 714 } 715 716 717 int KRB5_LIB_FUNCTION 718 krb5_config_vget_int_default (krb5_context context, 719 const krb5_config_section *c, 720 int def_value, 721 va_list args) 722 { 723 const char *str; 724 str = krb5_config_vget_string (context, c, args); 725 if(str == NULL) 726 return def_value; 727 else { 728 char *endptr; 729 long l; 730 l = strtol(str, &endptr, 0); 731 if (endptr == str) 732 return def_value; 733 else 734 return l; 735 } 736 } 737 738 int KRB5_LIB_FUNCTION 739 krb5_config_vget_int (krb5_context context, 740 const krb5_config_section *c, 741 va_list args) 742 { 743 return krb5_config_vget_int_default (context, c, -1, args); 744 } 745 746 int KRB5_LIB_FUNCTION 747 krb5_config_get_int_default (krb5_context context, 748 const krb5_config_section *c, 749 int def_value, 750 ...) 751 { 752 va_list ap; 753 int ret; 754 va_start(ap, def_value); 755 ret = krb5_config_vget_int_default(context, c, def_value, ap); 756 va_end(ap); 757 return ret; 758 } 759 760 int KRB5_LIB_FUNCTION 761 krb5_config_get_int (krb5_context context, 762 const krb5_config_section *c, 763 ...) 764 { 765 va_list ap; 766 int ret; 767 va_start(ap, c); 768 ret = krb5_config_vget_int (context, c, ap); 769 va_end(ap); 770 return ret; 771 } 772