1 #include "compat.h" 2 #include "libconfig.h" 3 #include "libconfig_private.h" 4 #include "conf_section.h" 5 #include "conf_apache.h" 6 #include "conf_colon.h" 7 #include "conf_equal.h" 8 #include "conf_space.h" 9 #include "conf_xml.h" 10 11 #ifdef HAVE_STRING_H 12 #include <string.h> 13 #endif 14 15 #ifdef HAVE_STDLIB_H 16 #include <stdlib.h> 17 #endif 18 19 #ifdef HAVE_CTYPE_H 20 #include <ctype.h> 21 #endif 22 23 #ifdef HAVE_STDIO_H 24 #include <stdio.h> 25 #endif 26 27 #ifdef HAVE_UNISTD_H 28 #include <unistd.h> 29 #endif 30 31 #ifdef HAVE_SYS_TYPES_H 32 #include <sys/types.h> 33 #endif 34 35 #ifdef HAVE_PWD_H 36 #include <pwd.h> 37 #endif 38 39 #ifdef HAVE_NETDB_H 40 #include <netdb.h> 41 #endif 42 43 struct lc_varhandler_st *varhandlers = NULL; 44 lc_err_t lc_errno = LC_ERR_NONE; 45 const char *lc_err_usererrmsg = NULL; 46 const char *lc_errfile = NULL; 47 int lc_optind = 0; 48 int lc_errline = 0; 49 50 extern char **environ; 51 52 static int lc_process_var_string(void *data, const char *value, const char **endptr) { 53 char **dataval; 54 55 dataval = data; 56 *dataval = strdup(value); 57 58 *endptr = NULL; 59 60 return(0); 61 } 62 63 static int lc_process_var_cidr(void *data, const char *value, const char **endptr) { 64 return(-1); 65 } 66 67 static int lc_process_var_hostname4(uint32_t *data, const char *value, const char **endptr) { 68 struct hostent *ghbn_ret; 69 70 ghbn_ret = gethostbyname(value); 71 if (ghbn_ret == NULL) { 72 return(-1); 73 } 74 75 if (ghbn_ret->h_length != 4) { 76 return(-1); 77 } 78 79 if (ghbn_ret->h_addr_list[0] == 0) { 80 return(-1); 81 } 82 83 memcpy(data, ghbn_ret->h_addr_list[0], sizeof(*data)); 84 85 return(0); 86 } 87 88 static int lc_process_var_hostname6(void *data, const char *value, const char **endptr) { 89 return(-1); 90 } 91 92 static int lc_process_var_ip4(uint32_t *data, const char *value, const char **endptr) { 93 uint32_t ipval = 0, curr_ipval = 0; 94 const char *valptr; 95 int retval = 0; 96 int dotcount = 0; 97 98 for (valptr = value; *valptr; valptr++) { 99 if (!isdigit(*valptr)) { 100 if (*valptr == '.' || *valptr == ',') { 101 dotcount++; 102 if (dotcount >= 4) { 103 retval = -1; 104 break; 105 } 106 107 if (curr_ipval > 255) { 108 retval = -1; 109 break; 110 } 111 112 /* For lists */ 113 if (*valptr == ',') { 114 break; 115 } 116 117 ipval |= curr_ipval << ((dotcount - 1) * 8); 118 curr_ipval = 0; 119 120 continue; 121 } else { 122 retval = -1; 123 break; 124 } 125 } 126 127 curr_ipval *= 10; 128 curr_ipval += *valptr - '0'; 129 } 130 131 if (curr_ipval > 255) { 132 retval = -1; 133 } 134 135 if (retval == 0) { 136 ipval |= curr_ipval << 24; 137 *data = ipval; 138 } 139 140 return(retval); 141 } 142 143 static int lc_process_var_ip6(void *data, const char *value, const char **endptr) { 144 return(-1); 145 } 146 147 static int lc_process_var_addr4(uint32_t *data, const char *value, const char **endptr) { 148 int lc_pv_ret; 149 150 lc_pv_ret = lc_process_var_ip4(data, value, endptr); 151 if (lc_pv_ret == 0) { 152 return(lc_pv_ret); 153 } 154 155 lc_pv_ret = lc_process_var_hostname4(data, value, endptr); 156 if (lc_pv_ret == 0) { 157 return(lc_pv_ret); 158 } 159 160 return(-1); 161 } 162 163 static int lc_process_var_addr6(void *data, const char *value, const char **endptr) { 164 int lc_pv_ret; 165 166 lc_pv_ret = lc_process_var_ip6(data, value, endptr); 167 if (lc_pv_ret == 0) { 168 return(lc_pv_ret); 169 } 170 171 lc_pv_ret = lc_process_var_hostname6(data, value, endptr); 172 if (lc_pv_ret == 0) { 173 return(lc_pv_ret); 174 } 175 return(-1); 176 } 177 178 static int lc_process_var_longlong(long long *data, const char *value, const char **endptr) { 179 *data = strtoll(value, (char **) endptr, 10); 180 181 return(0); 182 } 183 184 static int lc_process_var_long(long *data, const char *value, const char **endptr) { 185 *data = strtoll(value, (char **) endptr, 10); 186 187 return(0); 188 } 189 190 static int lc_process_var_int(int *data, const char *value, const char **endptr) { 191 *data = strtoll(value, (char **) endptr, 10); 192 193 return(0); 194 } 195 196 static int lc_process_var_short(short *data, const char *value, const char **endptr) { 197 *data = strtoll(value, (char **) endptr, 10); 198 199 return(0); 200 } 201 202 static int lc_process_var_bool_byexistance(int *data, const char *value, const char **endptr) { 203 *data = 1; 204 205 *endptr = NULL; 206 207 return(0); 208 } 209 210 static int lc_process_var_bool(int *data, const char *value, const char **endptr) { 211 char *trueval[] = {"enable", "true", "yes", "on", "y", "1"}; 212 char *falseval[] = {"disable", "false", "no", "off", "n", "0"}; 213 size_t chkvallen, vallen; 214 int i; 215 216 *data = -1; 217 218 vallen = strlen(value); 219 220 for (i = 0; i < (sizeof(trueval) / sizeof(*trueval)); i++) { 221 chkvallen = strlen(trueval[i]); 222 223 /* 224 * Skip if there's no way we could find a match here. 225 */ 226 if (chkvallen > vallen) { 227 continue; 228 } 229 230 /* 231 * Skip if there is no partial match. 232 */ 233 if (strncasecmp(value, trueval[i], chkvallen) != 0) { 234 continue; 235 } 236 237 if (value[chkvallen] == '\0' || value[chkvallen] == ',' || \ 238 value[chkvallen] == ' ') { 239 /* Declare a winner and set the next token. */ 240 *endptr = value + chkvallen; 241 *data = 1; 242 return(0); 243 } 244 } 245 246 for (i = 0; i < (sizeof(falseval) / sizeof(*falseval)); i++) { 247 chkvallen = strlen(falseval[i]); 248 249 /* 250 * Skip if there's no way we could find a match here. 251 */ 252 if (chkvallen > vallen) { 253 continue; 254 } 255 256 /* 257 * Skip if there is no partial match. 258 */ 259 if (strncasecmp(value, falseval[i], chkvallen) != 0) { 260 continue; 261 } 262 263 if (value[chkvallen] == '\0' || value[chkvallen] == ',' || \ 264 value[chkvallen] == ' ') { 265 /* Declare a winner and set the next token. */ 266 *endptr = value + chkvallen; 267 *data = 0; 268 return(0); 269 } 270 } 271 272 lc_errno = LC_ERR_BADFORMAT; 273 return(-1); 274 } 275 276 static unsigned long long lc_process_size(const char *value, const char **endptr) { 277 unsigned long long retval = 0; 278 char *mult = NULL; 279 280 retval = strtoll(value, &mult, 10); 281 if (mult != NULL) { 282 switch (tolower(mult[0])) { 283 case 'p': 284 retval *= 1125899906842624LLU; 285 break; 286 case 't': 287 retval *= 1958505086976LLU; 288 break; 289 case 'g': 290 retval *= 1073741824; 291 break; 292 case 'm': 293 retval *= 1048576; 294 break; 295 case 'k': 296 retval *= 1024; 297 break; 298 default: 299 break; 300 } 301 } 302 303 return(retval); 304 } 305 306 static int lc_process_var_sizelonglong(long long *data, const char *value, const char **endptr) { 307 *data = lc_process_size(value, endptr); 308 309 return(0); 310 } 311 312 static int lc_process_var_sizelong(long *data, const char *value, const char **endptr) { 313 *data = lc_process_size(value, endptr); 314 315 return(0); 316 } 317 318 static int lc_process_var_sizeint(int *data, const char *value, const char **endptr) { 319 *data = lc_process_size(value, endptr); 320 321 return(0); 322 } 323 324 static int lc_process_var_sizeshort(short *data, const char *value, const char **endptr) { 325 *data = lc_process_size(value, endptr); 326 327 return(0); 328 } 329 330 static int lc_process_var_sizesizet(size_t *data, const char *value, const char **endptr) { 331 *data = lc_process_size(value, endptr); 332 333 return(0); 334 } 335 336 static int lc_process_var_float(float *data, const char *value, const char **endptr) { 337 #ifdef HAVE_STRTOF 338 *data = strtof(value, endptr); 339 #else 340 *data = strtod(value, endptr); 341 #endif 342 343 return(0); 344 } 345 346 static int lc_process_var_double(double *data, const char *value, const char **endptr) { 347 *data = strtod(value, endptr); 348 349 return(0); 350 } 351 352 353 int lc_handle_type(lc_var_type_t type, const char *value, void *data) { 354 const char *next; 355 int is_list; 356 357 is_list = type & LC_VAR_LIST; 358 359 if (is_list == LC_VAR_LIST) { 360 /* XXX */ 361 } 362 363 switch (type) { 364 case LC_VAR_STRING: 365 return(lc_process_var_string(data, value, &next)); 366 break; 367 case LC_VAR_LONG_LONG: 368 return(lc_process_var_longlong(data, value, &next)); 369 break; 370 case LC_VAR_LONG: 371 return(lc_process_var_long(data, value, &next)); 372 break; 373 case LC_VAR_INT: 374 return(lc_process_var_int(data, value, &next)); 375 break; 376 case LC_VAR_SHORT: 377 return(lc_process_var_short(data, value, &next)); 378 break; 379 case LC_VAR_BOOL: 380 return(lc_process_var_bool(data, value, &next)); 381 break; 382 case LC_VAR_SIZE_LONG_LONG: 383 return(lc_process_var_sizelonglong(data, value, &next)); 384 break; 385 case LC_VAR_SIZE_LONG: 386 return(lc_process_var_sizelong(data, value, &next)); 387 break; 388 case LC_VAR_SIZE_INT: 389 return(lc_process_var_sizeint(data, value, &next)); 390 break; 391 case LC_VAR_SIZE_SHORT: 392 return(lc_process_var_sizeshort(data, value, &next)); 393 break; 394 case LC_VAR_BOOL_BY_EXISTANCE: 395 return(lc_process_var_bool_byexistance(data, value, &next)); 396 break; 397 case LC_VAR_SIZE_SIZE_T: 398 return(lc_process_var_sizesizet(data, value, &next)); 399 break; 400 case LC_VAR_IP: 401 case LC_VAR_IP4: 402 return(lc_process_var_ip4(data, value, &next)); 403 break; 404 case LC_VAR_IP6: 405 return(lc_process_var_ip6(data, value, &next)); 406 break; 407 case LC_VAR_ADDR: 408 case LC_VAR_ADDR4: 409 return(lc_process_var_addr4(data, value, &next)); 410 case LC_VAR_ADDR6: 411 return(lc_process_var_addr6(data, value, &next)); 412 case LC_VAR_HOSTNAME: 413 case LC_VAR_HOSTNAME4: 414 return(lc_process_var_hostname4(data, value, &next)); 415 break; 416 case LC_VAR_HOSTNAME6: 417 return(lc_process_var_hostname6(data, value, &next)); 418 break; 419 case LC_VAR_CIDR: 420 return(lc_process_var_cidr(data, value, &next)); 421 break; 422 case LC_VAR_DOUBLE: 423 return(lc_process_var_double(data, value, &next)); 424 break; 425 case LC_VAR_FLOAT: 426 return(lc_process_var_float(data, value, &next)); 427 break; 428 case LC_VAR_TIME: 429 case LC_VAR_DATE: 430 case LC_VAR_FILENAME: 431 case LC_VAR_DIRECTORY: 432 #ifdef DEBUG 433 fprintf(stderr, "Not implemented yet!\n"); 434 #endif 435 return(-1); 436 case LC_VAR_NONE: 437 case LC_VAR_UNKNOWN: 438 case LC_VAR_SECTION: 439 case LC_VAR_SECTIONSTART: 440 case LC_VAR_SECTIONEND: 441 return(0); 442 case LC_VAR_LIST: 443 return(0); 444 } 445 446 return(-1); 447 } 448 449 static int lc_handle(struct lc_varhandler_st *handler, const char *var, const char *varargs, const char *value, lc_flags_t flags) { 450 const char *localvar = NULL; 451 int retval; 452 453 if (var != NULL) { 454 localvar = strrchr(var, '.'); 455 if (localvar == NULL) { 456 localvar = var; 457 } else { 458 localvar++; 459 } 460 } else { 461 localvar = NULL; 462 } 463 464 switch (handler->mode) { 465 case LC_MODE_CALLBACK: 466 if (handler->callback != NULL) { 467 retval = handler->callback(localvar, var, varargs, value, flags, handler->extra); 468 if (retval < 0) { 469 lc_errno = LC_ERR_CALLBACK; 470 } 471 472 return(retval); 473 } 474 break; 475 case LC_MODE_VAR: 476 return(lc_handle_type(handler->type, value, handler->data)); 477 break; 478 } 479 480 return(-1); 481 } 482 483 static int lc_process_environment(const char *appname) { 484 #ifndef ENABLE_SMALL 485 struct lc_varhandler_st *handler = NULL; 486 size_t appnamelen = 0; 487 char varnamebuf[128] = {0}; 488 char **currvar; 489 char *sep = NULL, *value = NULL, *cmd = NULL; 490 char *ucase_appname = NULL, *ucase_appname_itr = NULL; 491 char *lastcomponent_handler = NULL; 492 int varnamelen = 0; 493 char *local_lc_errfile; 494 int local_lc_errline; 495 496 /* Make sure we have an environment to screw with, if not, 497 no arguments were found to be in error */ 498 if (environ == NULL || appname == NULL) { 499 return(0); 500 } 501 502 local_lc_errfile = "<environment>"; 503 local_lc_errline = 0; 504 505 /* Allocate and create our uppercase appname. */ 506 ucase_appname = strdup(appname); 507 if (ucase_appname == NULL) { 508 lc_errfile = local_lc_errfile; 509 lc_errline = local_lc_errline; 510 lc_errno = LC_ERR_ENOMEM; 511 return(-1); 512 } 513 for (ucase_appname_itr = ucase_appname; *ucase_appname_itr != '\0'; ucase_appname_itr++) { 514 *ucase_appname_itr = toupper(*ucase_appname_itr); 515 } 516 517 appnamelen = strlen(ucase_appname); 518 519 for (currvar = environ; *currvar != NULL; currvar++) { 520 /* If it doesn't begin with our appname ignore it completely. */ 521 if (strncmp(*currvar, ucase_appname, appnamelen) != 0) { 522 continue; 523 } 524 525 /* Find our seperator. */ 526 sep = strchr(*currvar, '='); 527 if (sep == NULL) { 528 continue; 529 } 530 531 varnamelen = sep - *currvar; 532 533 /* Skip variables that would overflow our buffer. */ 534 if (varnamelen >= sizeof(varnamebuf)) { 535 continue; 536 } 537 538 strncpy(varnamebuf, *currvar, varnamelen); 539 540 varnamebuf[varnamelen] = '\0'; 541 value = sep + 1; 542 543 /* We ignore APPNAME by itself. */ 544 if (strlen(varnamebuf) <= appnamelen) { 545 continue; 546 } 547 548 /* Further it must be <APPNAME>_ */ 549 if (varnamebuf[appnamelen] != '_') { 550 continue; 551 } 552 553 cmd = varnamebuf + appnamelen + 1; 554 555 /* We don't allow section specifiers, for reasons see notes in 556 the cmdline processor (below). */ 557 if (strchr(cmd, '.') != NULL) { 558 continue; 559 } 560 561 for (handler = varhandlers; handler != NULL; handler = handler->_next) { 562 if (handler->var == NULL) { 563 continue; 564 } 565 566 /* Skip handlers which don't agree with being 567 processed outside a config file */ 568 if (handler->type == LC_VAR_SECTION || 569 handler->type == LC_VAR_SECTIONSTART || 570 handler->type == LC_VAR_SECTIONEND || 571 handler->type == LC_VAR_UNKNOWN) { 572 continue; 573 } 574 575 /* Find the last part of the variable and compare it with 576 the option being processed, if a wildcard is given. */ 577 if (handler->var[0] == '*' && handler->var[1] == '.') { 578 lastcomponent_handler = strrchr(handler->var, '.'); 579 if (lastcomponent_handler == NULL) { 580 lastcomponent_handler = handler->var; 581 } else { 582 lastcomponent_handler++; 583 } 584 } else { 585 lastcomponent_handler = handler->var; 586 } 587 588 /* Ignore this handler if they don't match. */ 589 if (strcasecmp(lastcomponent_handler, cmd) != 0) { 590 continue; 591 } 592 593 if (handler->type == LC_VAR_NONE || handler->type == LC_VAR_BOOL_BY_EXISTANCE) { 594 value = NULL; 595 } 596 597 /* We ignore errors from the environment variables, 598 they're mostly insignificant. */ 599 lc_handle(handler, cmd, NULL, value, LC_FLAGS_ENVIRON); 600 601 break; 602 } 603 } 604 605 free(ucase_appname); 606 607 #endif 608 return(0); 609 } 610 611 static int lc_process_cmdline(int argc, char **argv) { 612 struct lc_varhandler_st *handler = NULL; 613 char *cmdarg = NULL, *cmdoptarg = NULL; 614 char *lastcomponent_handler = NULL; 615 char **newargv = NULL; 616 char *usedargv = NULL; 617 int cmdargidx = 0; 618 int newargvidx = 0; 619 int retval = 0, chkretval = 0; 620 int ch = 0; 621 char *local_lc_errfile; 622 int local_lc_errline; 623 624 local_lc_errfile = "<cmdline>"; 625 local_lc_errline = 0; 626 627 /* Allocate "argc + 1" (+1 for the NULL terminator) elements. */ 628 newargv = malloc((argc + 1) * sizeof(*newargv)); 629 if (newargv == NULL) { 630 lc_errfile = local_lc_errfile; 631 lc_errline = local_lc_errline; 632 lc_errno = LC_ERR_ENOMEM; 633 return(-1); 634 } 635 newargv[newargvidx++] = argv[0]; 636 newargv[argc] = NULL; 637 638 /* Allocate space to indicate which arguments have been used. */ 639 usedargv = malloc(argc * sizeof(*usedargv)); 640 if (usedargv == NULL) { 641 lc_errfile = local_lc_errfile; 642 lc_errline = local_lc_errline; 643 lc_errno = LC_ERR_ENOMEM; 644 free(newargv); 645 return(-1); 646 } 647 for (cmdargidx = 0; cmdargidx < argc; cmdargidx++) { 648 usedargv[cmdargidx] = 0; 649 } 650 651 for (cmdargidx = 1; cmdargidx < argc; cmdargidx++) { 652 cmdarg = argv[cmdargidx]; 653 654 /* Make sure we have an argument here. */ 655 if (cmdarg == NULL) { 656 break; 657 } 658 659 /* If the argument isn't an option, skip. */ 660 if (cmdarg[0] != '-') { 661 continue; 662 } 663 664 /* Setup a pointer in the new array for the actual argument. */ 665 newargv[newargvidx++] = cmdarg; 666 usedargv[cmdargidx] = 1; 667 668 /* Then shift the argument past the '-' so we can ignore it. */ 669 cmdarg++; 670 671 /* Handle long options. */ 672 if (cmdarg[0] == '-') { 673 cmdarg++; 674 675 /* Don't process arguments after the '--' option. */ 676 if (cmdarg[0] == '\0') { 677 break; 678 } 679 680 /* Look for a variable name that matches */ 681 for (handler = varhandlers; handler != NULL; handler = handler->_next) { 682 /* Skip handlers with no variable name. */ 683 if (handler->var == NULL) { 684 continue; 685 } 686 /* Skip handlers which don't agree with being 687 processed on the command line. */ 688 if (handler->type == LC_VAR_SECTION || 689 handler->type == LC_VAR_SECTIONSTART || 690 handler->type == LC_VAR_SECTIONEND || 691 handler->type == LC_VAR_UNKNOWN) { 692 continue; 693 } 694 695 /* Find the last part of the variable and compare it with 696 the option being processed, if a wildcard is given. */ 697 if (handler->var[0] == '*' && handler->var[1] == '.') { 698 lastcomponent_handler = strrchr(handler->var, '.'); 699 if (lastcomponent_handler == NULL) { 700 lastcomponent_handler = handler->var; 701 } else { 702 lastcomponent_handler++; 703 } 704 } else { 705 /* Disallow use of the fully qualified name 706 since there was no sectionstart portion 707 we cannot allow it to handle children of it. */ 708 if (strchr(cmdarg, '.') != NULL) { 709 continue; 710 } 711 lastcomponent_handler = handler->var; 712 } 713 714 /* Ignore this handler if they don't match. */ 715 if (strcasecmp(lastcomponent_handler, cmdarg) != 0) { 716 continue; 717 } 718 719 if (handler->type == LC_VAR_NONE || handler->type == LC_VAR_BOOL_BY_EXISTANCE) { 720 cmdoptarg = NULL; 721 } else { 722 cmdargidx++; 723 if (cmdargidx >= argc) { 724 fprintf(stderr, "Argument required.\n"); 725 lc_errfile = local_lc_errfile; 726 lc_errline = local_lc_errline; 727 lc_errno = LC_ERR_BADFORMAT; 728 free(usedargv); 729 free(newargv); 730 return(-1); 731 } 732 cmdoptarg = argv[cmdargidx]; 733 newargv[newargvidx++] = cmdoptarg; 734 usedargv[cmdargidx] = 1; 735 } 736 737 chkretval = lc_handle(handler, handler->var, NULL, cmdoptarg, LC_FLAGS_CMDLINE); 738 if (chkretval < 0) { 739 retval = -1; 740 } 741 742 break; 743 } 744 745 if (handler == NULL) { 746 fprintf(stderr, "Unknown option: --%s\n", cmdarg); 747 lc_errfile = local_lc_errfile; 748 lc_errline = local_lc_errline; 749 lc_errno = LC_ERR_INVCMD; 750 free(usedargv); 751 free(newargv); 752 return(-1); 753 } 754 } else { 755 for (; *cmdarg != '\0'; cmdarg++) { 756 ch = *cmdarg; 757 758 for (handler = varhandlers; handler != NULL; handler = handler->_next) { 759 if (handler->opt != ch || handler->opt == '\0') { 760 continue; 761 } 762 /* Skip handlers which don't agree with being 763 processed on the command line. */ 764 if (handler->type == LC_VAR_SECTION || 765 handler->type == LC_VAR_SECTIONSTART || 766 handler->type == LC_VAR_SECTIONEND || 767 handler->type == LC_VAR_UNKNOWN) { 768 continue; 769 } 770 771 if (handler->type == LC_VAR_NONE || handler->type == LC_VAR_BOOL_BY_EXISTANCE) { 772 cmdoptarg = NULL; 773 } else { 774 cmdargidx++; 775 if (cmdargidx >= argc) { 776 fprintf(stderr, "Argument required.\n"); 777 lc_errfile = local_lc_errfile; 778 lc_errline = local_lc_errline; 779 lc_errno = LC_ERR_BADFORMAT; 780 free(usedargv); 781 free(newargv); 782 return(-1); 783 } 784 cmdoptarg = argv[cmdargidx]; 785 newargv[newargvidx++] = cmdoptarg; 786 usedargv[cmdargidx] = 1; 787 } 788 789 chkretval = lc_handle(handler, handler->var, NULL, cmdoptarg, LC_FLAGS_CMDLINE); 790 if (chkretval < 0) { 791 lc_errfile = local_lc_errfile; 792 lc_errline = local_lc_errline; 793 retval = -1; 794 } 795 796 break; 797 } 798 799 if (handler == NULL) { 800 fprintf(stderr, "Unknown option: -%c\n", ch); 801 lc_errfile = local_lc_errfile; 802 lc_errline = local_lc_errline; 803 lc_errno = LC_ERR_INVCMD; 804 free(usedargv); 805 free(newargv); 806 return(-1); 807 } 808 } 809 } 810 } 811 812 if (retval >= 0) { 813 lc_optind = newargvidx; 814 for (cmdargidx = 1; cmdargidx < argc; cmdargidx++) { 815 if (usedargv[cmdargidx] != 0) { 816 continue; 817 } 818 819 cmdarg = argv[cmdargidx]; 820 821 newargv[newargvidx++] = cmdarg; 822 } 823 for (cmdargidx = 1; cmdargidx < argc; cmdargidx++) { 824 argv[cmdargidx] = newargv[cmdargidx]; 825 } 826 } 827 828 free(usedargv); 829 free(newargv); 830 831 return(retval); 832 } 833 834 835 int lc_process_var(const char *var, const char *varargs, const char *value, lc_flags_t flags) { 836 struct lc_varhandler_st *handler = NULL; 837 const char *lastcomponent_handler = NULL, *lastcomponent_var = NULL; 838 839 lastcomponent_var = strrchr(var, '.'); 840 if (lastcomponent_var == NULL) { 841 lastcomponent_var = var; 842 } else { 843 lastcomponent_var++; 844 } 845 846 for (handler = varhandlers; handler != NULL; handler = handler->_next) { 847 /* If either handler->var or var is NULL, skip, unless both are NULL. */ 848 if (handler->var != var && (handler->var == NULL || var == NULL)) { 849 continue; 850 } 851 852 /* If both are not-NULL, compare them. */ 853 if (handler->var != NULL) { 854 /* Wild-card-ish match. */ 855 if (handler->var[0] == '*' && handler->var[1] == '.') { 856 /* Only compare the last components */ 857 858 lastcomponent_handler = strrchr(handler->var, '.') + 1; /* strrchr() won't return NULL, because we already checked it. */ 859 860 if (strcasecmp(lastcomponent_handler, lastcomponent_var) != 0) { 861 continue; 862 } 863 } else if (strcasecmp(handler->var, var) != 0) { 864 /* Exact (case-insensitive comparison) failed. */ 865 continue; 866 } 867 } 868 869 if (value == NULL && 870 handler->type != LC_VAR_NONE && 871 handler->type != LC_VAR_BOOL_BY_EXISTANCE && 872 handler->type != LC_VAR_SECTION && 873 handler->type != LC_VAR_SECTIONSTART && 874 handler->type != LC_VAR_SECTIONEND) { 875 lc_errno = LC_ERR_BADFORMAT; 876 break; 877 } 878 879 return(lc_handle(handler, var, varargs, value, flags)); 880 } 881 882 return(-1); 883 } 884 885 int lc_register_callback(const char *var, char opt, lc_var_type_t type, int (*callback)(const char *, const char *, const char *, const char *, lc_flags_t, void *), void *extra) { 886 struct lc_varhandler_st *newhandler = NULL; 887 888 newhandler = malloc(sizeof(*newhandler)); 889 890 if (newhandler == NULL) { 891 return(-1); 892 } 893 894 if (var == NULL) { 895 newhandler->var = NULL; 896 } else { 897 newhandler->var = strdup(var); 898 } 899 newhandler->mode = LC_MODE_CALLBACK; 900 newhandler->type = type; 901 newhandler->callback = callback; 902 newhandler->opt = opt; 903 newhandler->extra = extra; 904 newhandler->_next = varhandlers; 905 906 varhandlers = newhandler; 907 908 return(0); 909 } 910 911 int lc_register_var(const char *var, lc_var_type_t type, void *data, char opt) { 912 struct lc_varhandler_st *newhandler = NULL; 913 914 newhandler = malloc(sizeof(*newhandler)); 915 916 if (newhandler == NULL) { 917 return(-1); 918 } 919 920 if (var == NULL) { 921 newhandler->var = NULL; 922 } else { 923 newhandler->var = strdup(var); 924 } 925 newhandler->mode = LC_MODE_VAR; 926 newhandler->type = type; 927 newhandler->data = data; 928 newhandler->opt = opt; 929 newhandler->extra = NULL; 930 newhandler->_next = varhandlers; 931 932 varhandlers = newhandler; 933 934 return(0); 935 } 936 937 int lc_process_file(const char *appname, const char *pathname, lc_conf_type_t type) { 938 int chkretval = 0; 939 940 switch (type) { 941 case LC_CONF_SECTION: 942 chkretval = lc_process_conf_section(appname, pathname); 943 break; 944 case LC_CONF_APACHE: 945 chkretval = lc_process_conf_apache(appname, pathname); 946 break; 947 case LC_CONF_COLON: 948 chkretval = lc_process_conf_colon(appname, pathname); 949 break; 950 case LC_CONF_EQUAL: 951 chkretval = lc_process_conf_equal(appname, pathname); 952 break; 953 case LC_CONF_SPACE: 954 chkretval = lc_process_conf_space(appname, pathname); 955 break; 956 case LC_CONF_XML: 957 chkretval = lc_process_conf_xml(appname, pathname); 958 break; 959 default: 960 chkretval = -1; 961 lc_errno = LC_ERR_INVDATA; 962 break; 963 } 964 965 return(chkretval); 966 } 967 968 static int lc_process_files(const char *appname, lc_conf_type_t type, const char *extraconfig) { 969 #ifdef HAVE_GETPWUID 970 struct passwd *pwinfo = NULL; 971 #endif 972 char configfiles[3][13][512] = {{{0}}}; 973 char *configfile = NULL; 974 char *homedir = NULL; 975 int configsetidx = 0, configidx = 0; 976 int chkretval = 0, retval = 0; 977 978 if (extraconfig != NULL) { 979 snprintf(configfiles[0][0], sizeof(**configfiles) - 1, "%s", extraconfig); 980 } 981 snprintf(configfiles[1][0], sizeof(**configfiles) - 1, "/etc/%s.cfg", appname); 982 snprintf(configfiles[1][1], sizeof(**configfiles) - 1, "/etc/%s.conf", appname); 983 snprintf(configfiles[1][2], sizeof(**configfiles) - 1, "/etc/%s/%s.cfg", appname, appname); 984 snprintf(configfiles[1][3], sizeof(**configfiles) - 1, "/etc/%s/%s.conf", appname, appname); 985 snprintf(configfiles[1][4], sizeof(**configfiles) - 1, "/usr/etc/%s.cfg", appname); 986 snprintf(configfiles[1][5], sizeof(**configfiles) - 1, "/usr/etc/%s.conf", appname); 987 snprintf(configfiles[1][6], sizeof(**configfiles) - 1, "/usr/etc/%s/%s.cfg", appname, appname); 988 snprintf(configfiles[1][7], sizeof(**configfiles) - 1, "/usr/etc/%s/%s.conf", appname, appname); 989 snprintf(configfiles[1][8], sizeof(**configfiles) - 1, "/usr/local/etc/%s.cfg", appname); 990 snprintf(configfiles[1][9], sizeof(**configfiles) - 1, "/usr/local/etc/%s.conf", appname); 991 snprintf(configfiles[1][10], sizeof(**configfiles) - 1, "/usr/local/etc/%s/%s.cfg", appname, appname); 992 snprintf(configfiles[1][11], sizeof(**configfiles) - 1, "/usr/local/etc/%s/%s.conf", appname, appname); 993 if (getuid() != 0) { 994 homedir = getenv("HOME"); 995 #ifdef HAVE_GETPWUID 996 if (homedir == NULL) { 997 pwinfo = getpwuid(getuid()); 998 if (pwinfo != NULL) { 999 homedir = pwinfo->pw_dir; 1000 } 1001 } 1002 #endif 1003 if (homedir != NULL) { 1004 if (strcmp(homedir, "/") != 0 && access(homedir, R_OK|W_OK|X_OK) == 0) { 1005 snprintf(configfiles[2][0], sizeof(**configfiles) - 1, "%s/.%src", homedir, appname); 1006 snprintf(configfiles[2][1], sizeof(**configfiles) - 1, "%s/.%s.cfg", homedir, appname); 1007 snprintf(configfiles[2][2], sizeof(**configfiles) - 1, "%s/.%s.conf", homedir, appname); 1008 snprintf(configfiles[2][3], sizeof(**configfiles) - 1, "%s/.%s/%s.cfg", homedir, appname, appname); 1009 snprintf(configfiles[2][4], sizeof(**configfiles) - 1, "%s/.%s/%s.conf", homedir, appname, appname); 1010 snprintf(configfiles[2][5], sizeof(**configfiles) - 1, "%s/.%s/config", homedir, appname); 1011 } 1012 } 1013 } 1014 1015 for (configsetidx = 0; configsetidx < 3; configsetidx++) { 1016 for (configidx = 0; configidx < 13; configidx++) { 1017 configfile = configfiles[configsetidx][configidx]; 1018 if (configfile[0] == '\0') { 1019 break; 1020 } 1021 if (access(configfile, R_OK) == 0) { 1022 chkretval = lc_process_file(appname, configfile, type); 1023 if (chkretval < 0) { 1024 retval = -1; 1025 } 1026 break; 1027 } 1028 } 1029 } 1030 1031 return(retval); 1032 } 1033 1034 void lc_cleanup(void) { 1035 struct lc_varhandler_st *handler = NULL, *next = NULL; 1036 1037 handler = varhandlers; 1038 while (handler != NULL) { 1039 if (handler->var != NULL) { 1040 free(handler->var); 1041 } 1042 1043 next = handler->_next; 1044 1045 free(handler); 1046 1047 handler = next; 1048 } 1049 1050 if (lc_err_usererrmsg) { 1051 free((char *) lc_err_usererrmsg); 1052 1053 lc_err_usererrmsg = NULL; 1054 } 1055 1056 varhandlers = NULL; 1057 1058 return; 1059 } 1060 1061 int lc_process(int argc, char **argv, const char *appname, lc_conf_type_t type, const char *extra) { 1062 int retval = 0, chkretval = 0; 1063 1064 /* Handle config files. */ 1065 chkretval = lc_process_files(appname, type, extra); 1066 if (chkretval < 0) { 1067 retval = -1; 1068 } 1069 1070 /* Handle environment variables.*/ 1071 chkretval = lc_process_environment(appname); 1072 if (chkretval < 0) { 1073 retval = -1; 1074 } 1075 1076 /* Handle command line arguments */ 1077 chkretval = lc_process_cmdline(argc, argv); 1078 if (chkretval < 0) { 1079 retval = -1; 1080 } 1081 1082 return(retval); 1083 } 1084 1085 1086 lc_err_t lc_geterrno(void) { 1087 lc_err_t retval; 1088 1089 retval = lc_errno; 1090 1091 return(retval); 1092 } 1093 1094 void lc_seterrstr(const char *usererrmsg) { 1095 lc_err_usererrmsg = strdup(usererrmsg); 1096 } 1097 1098 char *lc_geterrstr(void) { 1099 static char retval[512]; 1100 const char *errmsg = NULL; 1101 1102 switch (lc_errno) { 1103 case LC_ERR_NONE: 1104 errmsg = "Success"; 1105 break; 1106 case LC_ERR_INVCMD: 1107 errmsg = "Invalid command or option"; 1108 break; 1109 case LC_ERR_INVSECTION: 1110 errmsg = "Invalid section"; 1111 break; 1112 case LC_ERR_INVDATA: 1113 errmsg = "Invalid application data (internal error)"; 1114 break; 1115 case LC_ERR_BADFORMAT: 1116 errmsg = "Bad data specified or incorrect format."; 1117 break; 1118 case LC_ERR_CANTOPEN: 1119 errmsg = "Can't open file."; 1120 break; 1121 case LC_ERR_CALLBACK: 1122 if (lc_err_usererrmsg) { 1123 errmsg = lc_err_usererrmsg; 1124 } else { 1125 errmsg = "Error return from application handler."; 1126 } 1127 break; 1128 case LC_ERR_ENOMEM: 1129 errmsg = "Insuffcient memory."; 1130 break; 1131 } 1132 1133 /* 1134 * This is not part of the switch statement so we will get warnings 1135 * about unhandled enum values. 1136 */ 1137 if (errmsg == NULL) { 1138 errmsg = "Unknown error"; 1139 } 1140 1141 if (lc_errfile == NULL) { 1142 snprintf(retval, sizeof(retval), "%s:%i: %s", "<no file>", lc_errline, errmsg); 1143 } else { 1144 snprintf(retval, sizeof(retval), "%s:%i: %s", lc_errfile, lc_errline, errmsg); 1145 } 1146 1147 retval[sizeof(retval) - 1] = '\0'; 1148 1149 return(retval); 1150 } |