1 /* 2 * Copyright (c) 1997 - 2002 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,v 1.46 2002/09/10 19:04:55 joda Exp $"); 36 37 #ifndef HAVE_NETINFO 38 39 static krb5_error_code parse_section(char *p, krb5_config_section **s, 40 krb5_config_section **res, 41 const char **error_message); 42 static krb5_error_code parse_binding(FILE *f, unsigned *lineno, char *p, 43 krb5_config_binding **b, 44 krb5_config_binding **parent, 45 const char **error_message); 46 static krb5_error_code parse_list(FILE *f, unsigned *lineno, 47 krb5_config_binding **parent, 48 const char **error_message); 49 50 static krb5_config_section * 51 get_entry(krb5_config_section **parent, const char *name, int type) 52 { 53 krb5_config_section **q; 54 55 for(q = parent; *q != NULL; q = &(*q)->next) 56 if(type == krb5_config_list && 57 type == (*q)->type && 58 strcmp(name, (*q)->name) == 0) 59 return *q; 60 *q = calloc(1, sizeof(**q)); 61 if(*q == NULL) 62 return NULL; 63 (*q)->name = strdup(name); 64 (*q)->type = type; 65 if((*q)->name == NULL) { 66 free(*q); 67 *q = NULL; 68 return NULL; 69 } 70 return *q; 71 } 72 73 /* 74 * Parse a section: 75 * 76 * [section] 77 * foo = bar 78 * b = { 79 * a 80 * } 81 * ... 82 * 83 * starting at the line in `p', storing the resulting structure in 84 * `s' and hooking it into `parent'. 85 * Store the error message in `error_message'. 86 */ 87 88 static krb5_error_code 89 parse_section(char *p, krb5_config_section **s, krb5_config_section **parent, 90 const char **error_message) 91 { 92 char *p1; 93 krb5_config_section *tmp; 94 95 p1 = strchr (p + 1, ']'); 96 if (p1 == NULL) { 97 *error_message = "missing ]"; 98 return KRB5_CONFIG_BADFORMAT; 99 } 100 *p1 = '\0'; 101 tmp = get_entry(parent, p + 1, krb5_config_list); 102 if(tmp == NULL) { 103 *error_message = "out of memory"; 104 return KRB5_CONFIG_BADFORMAT; 105 } 106 *s = tmp; 107 return 0; 108 } 109 110 /* 111 * Parse a brace-enclosed list from `f', hooking in the structure at 112 * `parent'. 113 * Store the error message in `error_message'. 114 */ 115 116 static int 117 parse_list(FILE *f, unsigned *lineno, krb5_config_binding **parent, 118 const char **error_message) 119 { 120 char buf[BUFSIZ]; 121 int ret; 122 krb5_config_binding *b = NULL; 123 unsigned beg_lineno = *lineno; 124 125 while(fgets(buf, sizeof(buf), f) != NULL) { 126 char *p; 127 128 ++*lineno; 129 if (buf[strlen(buf) - 1] == '\n') 130 buf[strlen(buf) - 1] = '\0'; 131 p = buf; 132 while(isspace((unsigned char)*p)) 133 ++p; 134 if (*p == '#' || *p == ';' || *p == '\0') 135 continue; 136 while(isspace((unsigned char)*p)) 137 ++p; 138 if (*p == '}') 139 return 0; 140 if (*p == '\0') 141 continue; 142 ret = parse_binding (f, lineno, p, &b, parent, error_message); 143 if (ret) 144 return ret; 145 } 146 *lineno = beg_lineno; 147 *error_message = "unclosed {"; 148 return KRB5_CONFIG_BADFORMAT; 149 } 150 151 /* 152 * 153 */ 154 155 static int 156 parse_binding(FILE *f, unsigned *lineno, char *p, 157 krb5_config_binding **b, krb5_config_binding **parent, 158 const char **error_message) 159 { 160 krb5_config_binding *tmp; 161 char *p1, *p2; 162 int ret = 0; 163 164 p1 = p; 165 while (*p && *p != '=' && !isspace((unsigned char)*p)) 166 ++p; 167 if (*p == '\0') { 168 *error_message = "missing ="; 169 return KRB5_CONFIG_BADFORMAT; 170 } 171 p2 = p; 172 while (isspace((unsigned char)*p)) 173 ++p; 174 if (*p != '=') { 175 *error_message = "missing ="; 176 return KRB5_CONFIG_BADFORMAT; 177 } 178 ++p; 179 while(isspace((unsigned char)*p)) 180 ++p; 181 *p2 = '\0'; 182 if (*p == '{') { 183 tmp = get_entry(parent, p1, krb5_config_list); 184 if (tmp == NULL) { 185 *error_message = "out of memory"; 186 return KRB5_CONFIG_BADFORMAT; 187 } 188 ret = parse_list (f, lineno, &tmp->u.list, error_message); 189 } else { 190 tmp = get_entry(parent, p1, krb5_config_string); 191 if (tmp == NULL) { 192 *error_message = "out of memory"; 193 return KRB5_CONFIG_BADFORMAT; 194 } 195 p1 = p; 196 p = p1 + strlen(p1); 197 while(p > p1 && isspace((unsigned char)*(p-1))) 198 --p; 199 *p = '\0'; 200 tmp->u.string = strdup(p1); 201 } 202 *b = tmp; 203 return ret; 204 } 205 206 /* 207 * Parse the config file `fname', generating the structures into `res' 208 * returning error messages in `error_message' 209 */ 210 211 static krb5_error_code 212 krb5_config_parse_file_debug (const char *fname, 213 krb5_config_section **res, 214 unsigned *lineno, 215 const char **error_message) 216 { 217 FILE *f; 218 krb5_config_section *s; 219 krb5_config_binding *b; 220 char buf[BUFSIZ]; 221 krb5_error_code ret = 0; 222 223 s = NULL; 224 b = NULL; 225 *lineno = 0; 226 f = fopen (fname, "r"); 227 if (f == NULL) { 228 *error_message = "cannot open file"; 229 return ENOENT; 230 } 231 while (fgets(buf, sizeof(buf), f) != NULL) { 232 char *p; 233 234 ++*lineno; 235 if(buf[strlen(buf) - 1] == '\n') 236 buf[strlen(buf) - 1] = '\0'; 237 p = buf; 238 while(isspace((unsigned char)*p)) 239 ++p; 240 if (*p == '#' || *p == ';') 241 continue; 242 if (*p == '[') { 243 ret = parse_section(p, &s, res, error_message); 244 if (ret) { 245 goto out; 246 } 247 b = NULL; 248 } else if (*p == '}') { 249 *error_message = "unmatched }"; 250 ret = EINVAL; /* XXX */ 251 goto out; 252 } else if(*p != '\0') { 253 ret = parse_binding(f, lineno, p, &b, &s->u.list, error_message); 254 if (ret) 255 goto out; 256 } 257 } 258 out: 259 fclose (f); 260 return ret; 261 } 262 263 krb5_error_code 264 krb5_config_parse_file_multi (krb5_context context, 265 const char *fname, 266 krb5_config_section **res) 267 { 268 const char *str; 269 unsigned lineno; 270 krb5_error_code ret; 271 272 ret = krb5_config_parse_file_debug (fname, res, &lineno, &str); 273 if (ret) { 274 krb5_set_error_string (context, "%s:%u: %s", fname, lineno, str); 275 return ret; 276 } 277 return 0; 278 } 279 280 krb5_error_code 281 krb5_config_parse_file (krb5_context context, 282 const char *fname, 283 krb5_config_section **res) 284 { 285 *res = NULL; 286 return krb5_config_parse_file_multi(context, fname, res); 287 } 288 289 #endif /* !HAVE_NETINFO */ 290 291 static void 292 free_binding (krb5_context context, krb5_config_binding *b) 293 { 294 krb5_config_binding *next_b; 295 296 while (b) { 297 free (b->name); 298 if (b->type == krb5_config_string) 299 free (b->u.string); 300 else if (b->type == krb5_config_list) 301 free_binding (context, b->u.list); 302 else 303 krb5_abortx(context, "unknown binding type (%d) in free_binding", 304 b->type); 305 next_b = b->next; 306 free (b); 307 b = next_b; 308 } 309 } 310 311 krb5_error_code 312 krb5_config_file_free (krb5_context context, krb5_config_section *s) 313 { 314 free_binding (context, s); 315 return 0; 316 } 317 318 const void * 319 krb5_config_get_next (krb5_context context, 320 const krb5_config_section *c, 321 const krb5_config_binding **pointer, 322 int type, 323 ...) 324 { 325 const char *ret; 326 va_list args; 327 328 va_start(args, type); 329 ret = krb5_config_vget_next (context, c, pointer, type, args); 330 va_end(args); 331 return ret; 332 } 333 334 static const void * 335 vget_next(krb5_context context, 336 const krb5_config_binding *b, 337 const krb5_config_binding **pointer, 338 int type, 339 const char *name, 340 va_list args) 341 { 342 const char *p = va_arg(args, const char *); 343 while(b != NULL) { 344 if(strcmp(b->name, name) == 0) { 345 if(b->type == type && p == NULL) { 346 *pointer = b; 347 return b->u.generic; 348 } else if(b->type == krb5_config_list && p != NULL) { 349 return vget_next(context, b->u.list, pointer, type, p, args); 350 } 351 } 352 b = b->next; 353 } 354 return NULL; 355 } 356 357 const void * 358 krb5_config_vget_next (krb5_context context, 359 const krb5_config_section *c, 360 const krb5_config_binding **pointer, 361 int type, 362 va_list args) 363 { 364 const krb5_config_binding *b; 365 const char *p; 366 367 if(c == NULL) 368 c = context->cf; 369 370 if (c == NULL) 371 return NULL; 372 373 if (*pointer == NULL) { 374 /* first time here, walk down the tree looking for the right 375 section */ 376 p = va_arg(args, const char *); 377 if (p == NULL) 378 return NULL; 379 return vget_next(context, c, pointer, type, p, args); 380 } 381 382 /* we were called again, so just look for more entries with the 383 same name and type */ 384 for (b = (*pointer)->next; b != NULL; b = b->next) { 385 if(strcmp(b->name, (*pointer)->name) == 0 && b->type == type) { 386 *pointer = b; 387 return b->u.generic; 388 } 389 } 390 return NULL; 391 } 392 393 const void * 394 krb5_config_get (krb5_context context, 395 const krb5_config_section *c, 396 int type, 397 ...) 398 { 399 const void *ret; 400 va_list args; 401 402 va_start(args, type); 403 ret = krb5_config_vget (context, c, type, args); 404 va_end(args); 405 return ret; 406 } 407 408 const void * 409 krb5_config_vget (krb5_context context, 410 const krb5_config_section *c, 411 int type, 412 va_list args) 413 { 414 const krb5_config_binding *foo = NULL; 415 416 return krb5_config_vget_next (context, c, &foo, type, args); 417 } 418 419 const krb5_config_binding * 420 krb5_config_get_list (krb5_context context, 421 const krb5_config_section *c, 422 ...) 423 { 424 const krb5_config_binding *ret; 425 va_list args; 426 427 va_start(args, c); 428 ret = krb5_config_vget_list (context, c, args); 429 va_end(args); 430 return ret; 431 } 432 433 const krb5_config_binding * 434 krb5_config_vget_list (krb5_context context, 435 const krb5_config_section *c, 436 va_list args) 437 { 438 return krb5_config_vget (context, c, krb5_config_list, args); 439 } 440 441 const char * 442 krb5_config_get_string (krb5_context context, 443 const krb5_config_section *c, 444 ...) 445 { 446 const char *ret; 447 va_list args; 448 449 va_start(args, c); 450 ret = krb5_config_vget_string (context, c, args); 451 va_end(args); 452 return ret; 453 } 454 455 const char * 456 krb5_config_vget_string (krb5_context context, 457 const krb5_config_section *c, 458 va_list args) 459 { 460 return krb5_config_vget (context, c, krb5_config_string, args); 461 } 462 463 const char * 464 krb5_config_vget_string_default (krb5_context context, 465 const krb5_config_section *c, 466 const char *def_value, 467 va_list args) 468 { 469 const char *ret; 470 471 ret = krb5_config_vget_string (context, c, args); 472 if (ret == NULL) 473 ret = def_value; 474 return ret; 475 } 476 477 const char * 478 krb5_config_get_string_default (krb5_context context, 479 const krb5_config_section *c, 480 const char *def_value, 481 ...) 482 { 483 const char *ret; 484 va_list args; 485 486 va_start(args, def_value); 487 ret = krb5_config_vget_string_default (context, c, def_value, args); 488 va_end(args); 489 return ret; 490 } 491 492 char ** 493 krb5_config_vget_strings(krb5_context context, 494 const krb5_config_section *c, 495 va_list args) 496 { 497 char **strings = NULL; 498 int nstr = 0; 499 const krb5_config_binding *b = NULL; 500 const char *p; 501 502 while((p = krb5_config_vget_next(context, c, &b, 503 krb5_config_string, args))) { 504 char *tmp = strdup(p); 505 char *pos = NULL; 506 char *s; 507 if(tmp == NULL) 508 goto cleanup; 509 s = strtok_r(tmp, " \t", &pos); 510 while(s){ 511 char **tmp = realloc(strings, (nstr + 1) * sizeof(*strings)); 512 if(tmp == NULL) 513 goto cleanup; 514 strings = tmp; 515 strings[nstr] = strdup(s); 516 nstr++; 517 if(strings[nstr-1] == NULL) 518 goto cleanup; 519 s = strtok_r(NULL, " \t", &pos); 520 } 521 free(tmp); 522 } 523 if(nstr){ 524 char **tmp = realloc(strings, (nstr + 1) * sizeof(*strings)); 525 if(strings == NULL) 526 goto cleanup; 527 strings = tmp; 528 strings[nstr] = NULL; 529 } 530 return strings; 531 cleanup: 532 while(nstr--) 533 free(strings[nstr]); 534 free(strings); 535 return NULL; 536 537 } 538 539 char** 540 krb5_config_get_strings(krb5_context context, 541 const krb5_config_section *c, 542 ...) 543 { 544 va_list ap; 545 char **ret; 546 va_start(ap, c); 547 ret = krb5_config_vget_strings(context, c, ap); 548 va_end(ap); 549 return ret; 550 } 551 552 void 553 krb5_config_free_strings(char **strings) 554 { 555 char **s = strings; 556 while(s && *s){ 557 free(*s); 558 s++; 559 } 560 free(strings); 561 } 562 563 krb5_boolean 564 krb5_config_vget_bool_default (krb5_context context, 565 const krb5_config_section *c, 566 krb5_boolean def_value, 567 va_list args) 568 { 569 const char *str; 570 str = krb5_config_vget_string (context, c, args); 571 if(str == NULL) 572 return def_value; 573 if(strcasecmp(str, "yes") == 0 || 574 strcasecmp(str, "true") == 0 || 575 atoi(str)) return TRUE; 576 return FALSE; 577 } 578 579 krb5_boolean 580 krb5_config_vget_bool (krb5_context context, 581 const krb5_config_section *c, 582 va_list args) 583 { 584 return krb5_config_vget_bool_default (context, c, FALSE, args); 585 } 586 587 krb5_boolean 588 krb5_config_get_bool_default (krb5_context context, 589 const krb5_config_section *c, 590 krb5_boolean def_value, 591 ...) 592 { 593 va_list ap; 594 krb5_boolean ret; 595 va_start(ap, def_value); 596 ret = krb5_config_vget_bool_default(context, c, def_value, ap); 597 va_end(ap); 598 return ret; 599 } 600 601 krb5_boolean 602 krb5_config_get_bool (krb5_context context, 603 const krb5_config_section *c, 604 ...) 605 { 606 va_list ap; 607 krb5_boolean ret; 608 va_start(ap, c); 609 ret = krb5_config_vget_bool (context, c, ap); 610 va_end(ap); 611 return ret; 612 } 613 614 int 615 krb5_config_vget_time_default (krb5_context context, 616 const krb5_config_section *c, 617 int def_value, 618 va_list args) 619 { 620 const char *str; 621 str = krb5_config_vget_string (context, c, args); 622 if(str == NULL) 623 return def_value; 624 return parse_time (str, NULL); 625 } 626 627 int 628 krb5_config_vget_time (krb5_context context, 629 const krb5_config_section *c, 630 va_list args) 631 { 632 return krb5_config_vget_time_default (context, c, -1, args); 633 } 634 635 int 636 krb5_config_get_time_default (krb5_context context, 637 const krb5_config_section *c, 638 int def_value, 639 ...) 640 { 641 va_list ap; 642 int ret; 643 va_start(ap, def_value); 644 ret = krb5_config_vget_time_default(context, c, def_value, ap); 645 va_end(ap); 646 return ret; 647 } 648 649 int 650 krb5_config_get_time (krb5_context context, 651 const krb5_config_section *c, 652 ...) 653 { 654 va_list ap; 655 int ret; 656 va_start(ap, c); 657 ret = krb5_config_vget_time (context, c, ap); 658 va_end(ap); 659 return ret; 660 } 661 662 663 int 664 krb5_config_vget_int_default (krb5_context context, 665 const krb5_config_section *c, 666 int def_value, 667 va_list args) 668 { 669 const char *str; 670 str = krb5_config_vget_string (context, c, args); 671 if(str == NULL) 672 return def_value; 673 else { 674 char *endptr; 675 long l; 676 l = strtol(str, &endptr, 0); 677 if (endptr == str) 678 return def_value; 679 else 680 return l; 681 } 682 } 683 684 int 685 krb5_config_vget_int (krb5_context context, 686 const krb5_config_section *c, 687 va_list args) 688 { 689 return krb5_config_vget_int_default (context, c, -1, args); 690 } 691 692 int 693 krb5_config_get_int_default (krb5_context context, 694 const krb5_config_section *c, 695 int def_value, 696 ...) 697 { 698 va_list ap; 699 int ret; 700 va_start(ap, def_value); 701 ret = krb5_config_vget_int_default(context, c, def_value, ap); 702 va_end(ap); 703 return ret; 704 } 705 706 int 707 krb5_config_get_int (krb5_context context, 708 const krb5_config_section *c, 709 ...) 710 { 711 va_list ap; 712 int ret; 713 va_start(ap, c); 714 ret = krb5_config_vget_int (context, c, ap); 715 va_end(ap); 716 return ret; 717 } 718