diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-22 13:49:16 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-22 13:49:16 +0000 |
commit | 1cf4a0eb81ed85d222d3310c39ac89c84c13ca17 (patch) | |
tree | 11875bcafe1a1bb8b41ab1ef41d47c0a6d856326 | |
parent | 574c316e5ac576ba8f4aa07596dd21bca95eb333 (diff) | |
download | busybox-w32-1cf4a0eb81ed85d222d3310c39ac89c84c13ca17.tar.gz busybox-w32-1cf4a0eb81ed85d222d3310c39ac89c84c13ca17.tar.bz2 busybox-w32-1cf4a0eb81ed85d222d3310c39ac89c84c13ca17.zip |
httpd: simplify insane conf file parser
function old new delta
bb_simplify_abs_path_inplace - 98 +98
parse_expr 824 832 +8
passwd_main 1025 1027 +2
evalvar 1374 1376 +2
parse_command 1463 1460 -3
bb_simplify_path 137 55 -82
parse_conf 1572 1422 -150
------------------------------------------------------------------------------
(add/remove: 3/2 grow/shrink: 3/3 up/down: 126/-251) Total: -125 bytes
-rw-r--r-- | include/libbb.h | 2 | ||||
-rw-r--r-- | libbb/simplify_path.c | 32 | ||||
-rw-r--r-- | networking/httpd.c | 348 |
3 files changed, 194 insertions, 188 deletions
diff --git a/include/libbb.h b/include/libbb.h index 4de3e7915..3a94a0070 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -1093,6 +1093,8 @@ const char *get_signame(int number) FAST_FUNC; | |||
1093 | void print_signames(void) FAST_FUNC; | 1093 | void print_signames(void) FAST_FUNC; |
1094 | 1094 | ||
1095 | char *bb_simplify_path(const char *path) FAST_FUNC; | 1095 | char *bb_simplify_path(const char *path) FAST_FUNC; |
1096 | /* Returns ptr to NUL */ | ||
1097 | char *bb_simplify_abs_path_inplace(char *path) FAST_FUNC; | ||
1096 | 1098 | ||
1097 | #define FAIL_DELAY 3 | 1099 | #define FAIL_DELAY 3 |
1098 | extern void bb_do_delay(int seconds) FAST_FUNC; | 1100 | extern void bb_do_delay(int seconds) FAST_FUNC; |
diff --git a/libbb/simplify_path.c b/libbb/simplify_path.c index 367f1f04d..f80e3e8a5 100644 --- a/libbb/simplify_path.c +++ b/libbb/simplify_path.c | |||
@@ -6,22 +6,13 @@ | |||
6 | * | 6 | * |
7 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. | 7 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
8 | */ | 8 | */ |
9 | |||
10 | #include "libbb.h" | 9 | #include "libbb.h" |
11 | 10 | ||
12 | char* FAST_FUNC bb_simplify_path(const char *path) | 11 | char* FAST_FUNC bb_simplify_abs_path_inplace(char *start) |
13 | { | 12 | { |
14 | char *s, *start, *p; | 13 | char *s, *p; |
15 | 14 | ||
16 | if (path[0] == '/') | ||
17 | start = xstrdup(path); | ||
18 | else { | ||
19 | s = xrealloc_getcwd_or_warn(NULL); | ||
20 | start = concat_path_file(s, path); | ||
21 | free(s); | ||
22 | } | ||
23 | p = s = start; | 15 | p = s = start; |
24 | |||
25 | do { | 16 | do { |
26 | if (*p == '/') { | 17 | if (*p == '/') { |
27 | if (*s == '/') { /* skip duplicate (or initial) slash */ | 18 | if (*s == '/') { /* skip duplicate (or initial) slash */ |
@@ -47,7 +38,22 @@ char* FAST_FUNC bb_simplify_path(const char *path) | |||
47 | if ((p == start) || (*p != '/')) { /* not a trailing slash */ | 38 | if ((p == start) || (*p != '/')) { /* not a trailing slash */ |
48 | ++p; /* so keep last character */ | 39 | ++p; /* so keep last character */ |
49 | } | 40 | } |
50 | *p = 0; | 41 | *p = '\0'; |
42 | return p; | ||
43 | } | ||
44 | |||
45 | char* FAST_FUNC bb_simplify_path(const char *path) | ||
46 | { | ||
47 | char *s, *p; | ||
48 | |||
49 | if (path[0] == '/') | ||
50 | s = xstrdup(path); | ||
51 | else { | ||
52 | p = xrealloc_getcwd_or_warn(NULL); | ||
53 | s = concat_path_file(p, path); | ||
54 | free(p); | ||
55 | } | ||
51 | 56 | ||
52 | return start; | 57 | bb_simplify_abs_path_inplace(s); |
58 | return s; | ||
53 | } | 59 | } |
diff --git a/networking/httpd.c b/networking/httpd.c index 803a98b46..243d76f94 100644 --- a/networking/httpd.c +++ b/networking/httpd.c | |||
@@ -54,7 +54,7 @@ | |||
54 | * /adm:admin:setup # Require user admin, pwd setup on urls starting with /adm/ | 54 | * /adm:admin:setup # Require user admin, pwd setup on urls starting with /adm/ |
55 | * /adm:toor:PaSsWd # or user toor, pwd PaSsWd on urls starting with /adm/ | 55 | * /adm:toor:PaSsWd # or user toor, pwd PaSsWd on urls starting with /adm/ |
56 | * .au:audio/basic # additional mime type for audio.au files | 56 | * .au:audio/basic # additional mime type for audio.au files |
57 | * *.php:/path/php # running cgi.php scripts through an interpreter | 57 | * *.php:/path/php # run xxx.php through an interpreter |
58 | * | 58 | * |
59 | * A/D may be as a/d or allow/deny - only first char matters. | 59 | * A/D may be as a/d or allow/deny - only first char matters. |
60 | * Deny/Allow IP logic: | 60 | * Deny/Allow IP logic: |
@@ -115,8 +115,8 @@ | |||
115 | 115 | ||
116 | #define HEADER_READ_TIMEOUT 60 | 116 | #define HEADER_READ_TIMEOUT 60 |
117 | 117 | ||
118 | static const char default_path_httpd_conf[] ALIGN1 = "/etc"; | 118 | static const char DEFAULT_PATH_HTTPD_CONF[] ALIGN1 = "/etc"; |
119 | static const char httpd_conf[] ALIGN1 = "httpd.conf"; | 119 | static const char HTTPD_CONF[] ALIGN1 = "httpd.conf"; |
120 | static const char HTTP_200[] ALIGN1 = "HTTP/1.0 200 OK\r\n"; | 120 | static const char HTTP_200[] ALIGN1 = "HTTP/1.0 200 OK\r\n"; |
121 | 121 | ||
122 | typedef struct has_next_ptr { | 122 | typedef struct has_next_ptr { |
@@ -242,7 +242,7 @@ struct globals { | |||
242 | const char *bind_addr_or_port; | 242 | const char *bind_addr_or_port; |
243 | 243 | ||
244 | const char *g_query; | 244 | const char *g_query; |
245 | const char *configFile; | 245 | const char *opt_c_configFile; |
246 | const char *home_httpd; | 246 | const char *home_httpd; |
247 | const char *index_page; | 247 | const char *index_page; |
248 | 248 | ||
@@ -289,7 +289,7 @@ struct globals { | |||
289 | #define rmt_ip (G.rmt_ip ) | 289 | #define rmt_ip (G.rmt_ip ) |
290 | #define bind_addr_or_port (G.bind_addr_or_port) | 290 | #define bind_addr_or_port (G.bind_addr_or_port) |
291 | #define g_query (G.g_query ) | 291 | #define g_query (G.g_query ) |
292 | #define configFile (G.configFile ) | 292 | #define opt_c_configFile (G.opt_c_configFile ) |
293 | #define home_httpd (G.home_httpd ) | 293 | #define home_httpd (G.home_httpd ) |
294 | #define index_page (G.index_page ) | 294 | #define index_page (G.index_page ) |
295 | #define found_mime_type (G.found_mime_type ) | 295 | #define found_mime_type (G.found_mime_type ) |
@@ -452,14 +452,6 @@ static int scan_ip_mask(const char *str, unsigned *ipp, unsigned *maskp) | |||
452 | /* | 452 | /* |
453 | * Parse configuration file into in-memory linked list. | 453 | * Parse configuration file into in-memory linked list. |
454 | * | 454 | * |
455 | * The first non-white character is examined to determine if the config line | ||
456 | * is one of the following: | ||
457 | * .ext:mime/type # new mime type not compiled into httpd | ||
458 | * [adAD]:from # ip address allow/deny, * for wildcard | ||
459 | * /path:user:pass # username/password | ||
460 | * Ennn:error.html # error page for status nnn | ||
461 | * P:/url:[http://]hostname[:port]/new/path # reverse proxy | ||
462 | * | ||
463 | * Any previous IP rules are discarded. | 455 | * Any previous IP rules are discarded. |
464 | * If the flag argument is not SUBDIR_PARSE then all /path and mime rules | 456 | * If the flag argument is not SUBDIR_PARSE then all /path and mime rules |
465 | * are also discarded. That is, previous settings are retained if flag is | 457 | * are also discarded. That is, previous settings are retained if flag is |
@@ -469,99 +461,136 @@ static int scan_ip_mask(const char *str, unsigned *ipp, unsigned *maskp) | |||
469 | * path Path where to look for httpd.conf (without filename). | 461 | * path Path where to look for httpd.conf (without filename). |
470 | * flag Type of the parse request. | 462 | * flag Type of the parse request. |
471 | */ | 463 | */ |
472 | /* flag */ | 464 | /* flag param: */ |
473 | #define FIRST_PARSE 0 | 465 | enum { |
474 | #define SUBDIR_PARSE 1 | 466 | FIRST_PARSE = 0, /* path will be "/etc" */ |
475 | #define SIGNALED_PARSE 2 | 467 | SIGNALED_PARSE = 1, /* path will be "/etc" */ |
476 | #define FIND_FROM_HTTPD_ROOT 3 | 468 | SUBDIR_PARSE = 2, /* path will be derived from URL */ |
469 | }; | ||
477 | static void parse_conf(const char *path, int flag) | 470 | static void parse_conf(const char *path, int flag) |
478 | { | 471 | { |
472 | /* internally used extra flag state */ | ||
473 | enum { TRY_CURDIR_PARSE = 3 }; | ||
474 | |||
479 | FILE *f; | 475 | FILE *f; |
480 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH | 476 | const char *filename; |
481 | Htaccess *prev; | ||
482 | #endif | ||
483 | Htaccess *cur; | ||
484 | const char *filename = configFile; | ||
485 | char buf[160]; | 477 | char buf[160]; |
486 | char *p, *p0; | ||
487 | char *after_colon; | ||
488 | Htaccess_IP *pip; | ||
489 | 478 | ||
490 | /* discard old rules */ | 479 | /* discard old rules */ |
491 | free_Htaccess_IP_list(&ip_a_d); | 480 | free_Htaccess_IP_list(&ip_a_d); |
492 | flg_deny_all = 0; | 481 | flg_deny_all = 0; |
493 | /* retain previous auth and mime config only for subdir parse */ | 482 | /* retain previous auth and mime config only for subdir parse */ |
494 | if (flag != SUBDIR_PARSE) { | 483 | if (flag != SUBDIR_PARSE) { |
484 | free_Htaccess_list(&mime_a); | ||
495 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH | 485 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH |
496 | free_Htaccess_list(&g_auth); | 486 | free_Htaccess_list(&g_auth); |
497 | #endif | 487 | #endif |
498 | free_Htaccess_list(&mime_a); | ||
499 | #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR | 488 | #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR |
500 | free_Htaccess_list(&script_i); | 489 | free_Htaccess_list(&script_i); |
501 | #endif | 490 | #endif |
502 | } | 491 | } |
503 | 492 | ||
493 | filename = opt_c_configFile; | ||
504 | if (flag == SUBDIR_PARSE || filename == NULL) { | 494 | if (flag == SUBDIR_PARSE || filename == NULL) { |
505 | filename = alloca(strlen(path) + sizeof(httpd_conf) + 2); | 495 | filename = alloca(strlen(path) + sizeof(HTTPD_CONF) + 2); |
506 | sprintf((char *)filename, "%s/%s", path, httpd_conf); | 496 | sprintf((char *)filename, "%s/%s", path, HTTPD_CONF); |
507 | } | 497 | } |
508 | 498 | ||
509 | while ((f = fopen_for_read(filename)) == NULL) { | 499 | while ((f = fopen_for_read(filename)) == NULL) { |
510 | if (flag == SUBDIR_PARSE || flag == FIND_FROM_HTTPD_ROOT) { | 500 | if (flag >= SUBDIR_PARSE) { /* SUBDIR or TRY_CURDIR */ |
511 | /* config file not found, no changes to config */ | 501 | /* config file not found, no changes to config */ |
512 | return; | 502 | return; |
513 | } | 503 | } |
514 | if (configFile && flag == FIRST_PARSE) /* if -c option given */ | 504 | if (flag == FIRST_PARSE) { |
515 | bb_simple_perror_msg_and_die(filename); | 505 | /* -c CONFFILE given, but CONFFILE doesn't exist? */ |
516 | flag = FIND_FROM_HTTPD_ROOT; | 506 | if (opt_c_configFile) |
517 | filename = httpd_conf; | 507 | bb_simple_perror_msg_and_die(opt_c_configFile); |
508 | /* else: no -c, thus we looked at /etc/httpd.conf, | ||
509 | * and it's not there. try ./httpd.conf: */ | ||
510 | } | ||
511 | flag = TRY_CURDIR_PARSE; | ||
512 | filename = HTTPD_CONF; | ||
518 | } | 513 | } |
519 | 514 | ||
520 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH | 515 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH |
521 | prev = g_auth; | 516 | /* in "/file:user:pass" lines, we prepend path in subdirs */ |
522 | #endif | 517 | if (flag != SUBDIR_PARSE) |
523 | /* This could stand some work */ | 518 | path = ""; |
524 | while ((p0 = fgets(buf, sizeof(buf), f)) != NULL) { | 519 | #endif |
525 | after_colon = NULL; | 520 | /* The lines can be: |
526 | for (p = p0; *p0 != '\0' && *p0 != '#'; p0++) { | 521 | * |
527 | if (!isspace(*p0)) { | 522 | * I:default_index_file |
528 | *p++ = *p0; | 523 | * H:http_home |
529 | if (*p0 == ':' && after_colon == NULL) | 524 | * [AD]:IP[/mask] # allow/deny, * for wildcard |
530 | after_colon = p; | 525 | * Ennn:error.html # error page for status nnn |
526 | * P:/url:[http://]hostname[:port]/new/path # reverse proxy | ||
527 | * .ext:mime/type # mime type | ||
528 | * *.php:/path/php # run xxx.php through an interpreter | ||
529 | * /file:user:pass # username and password | ||
530 | */ | ||
531 | while (fgets(buf, sizeof(buf), f) != NULL) { | ||
532 | unsigned strlen_buf; | ||
533 | unsigned char ch; | ||
534 | char *after_colon = NULL; | ||
535 | |||
536 | { /* remove all whitespace, and # comments */ | ||
537 | char *p, *p0; | ||
538 | |||
539 | p = p0 = buf; | ||
540 | while ((ch = *p0++) != '\0' && ch != '#') { | ||
541 | if (!isspace(ch)) { | ||
542 | *p++ = ch; | ||
543 | if (ch == ':' && after_colon == NULL) | ||
544 | after_colon = p; | ||
545 | } | ||
531 | } | 546 | } |
547 | *p = '\0'; | ||
548 | strlen_buf = p - buf; | ||
532 | } | 549 | } |
533 | *p = '\0'; | ||
534 | 550 | ||
535 | /* test for empty or strange line */ | 551 | /* empty or strange line? */ |
536 | if (after_colon == NULL || *after_colon == '\0') | 552 | if (after_colon == NULL || *after_colon == '\0') |
553 | goto config_error; | ||
554 | |||
555 | ch = (buf[0] & ~0x20); /* toupper if it's a letter */ | ||
556 | |||
557 | if (ch == 'I') { | ||
558 | index_page = xstrdup(after_colon); | ||
537 | continue; | 559 | continue; |
538 | p0 = buf; | 560 | } |
539 | if (*p0 == 'd' || *p0 == 'a') | 561 | |
540 | *p0 -= 0x20; /* a/d -> A/D */ | 562 | /* do not allow jumping around using H in subdir's configs */ |
541 | if (*after_colon == '*') { | 563 | if (flag == FIRST_PARSE && ch == 'H') { |
542 | if (*p0 == 'D') { | 564 | home_httpd = xstrdup(after_colon); |
543 | /* memorize "deny all" */ | 565 | xchdir(home_httpd); |
544 | flg_deny_all = 1; | ||
545 | } | ||
546 | /* skip assumed "A:*", it is a default anyway */ | ||
547 | continue; | 566 | continue; |
548 | } | 567 | } |
549 | 568 | ||
550 | if (*p0 == 'A' || *p0 == 'D') { | 569 | if (ch == 'A' || ch == 'D') { |
551 | /* storing current config IP line */ | 570 | Htaccess_IP *pip; |
552 | pip = xzalloc(sizeof(Htaccess_IP)); | 571 | |
553 | if (scan_ip_mask(after_colon, &(pip->ip), &(pip->mask))) { | 572 | if (*after_colon == '*') { |
573 | if (ch == 'D') { | ||
574 | /* memorize "deny all" */ | ||
575 | flg_deny_all = 1; | ||
576 | } | ||
577 | /* skip assumed "A:*", it is a default anyway */ | ||
578 | continue; | ||
579 | } | ||
580 | /* store "allow/deny IP/mask" line */ | ||
581 | pip = xzalloc(sizeof(*pip)); | ||
582 | if (scan_ip_mask(after_colon, &pip->ip, &pip->mask)) { | ||
554 | /* IP{/mask} syntax error detected, protect all */ | 583 | /* IP{/mask} syntax error detected, protect all */ |
555 | *p0 = 'D'; | 584 | ch = 'D'; |
556 | pip->mask = 0; | 585 | pip->mask = 0; |
557 | } | 586 | } |
558 | pip->allow_deny = *p0; | 587 | pip->allow_deny = ch; |
559 | if (*p0 == 'D') { | 588 | if (ch == 'D') { |
560 | /* Deny:from_IP - prepend */ | 589 | /* Deny:from_IP - prepend */ |
561 | pip->next = ip_a_d; | 590 | pip->next = ip_a_d; |
562 | ip_a_d = pip; | 591 | ip_a_d = pip; |
563 | } else { | 592 | } else { |
564 | /* A:from_IP - append (thus D precedes A) */ | 593 | /* A:from_IP - append (thus all D's precedes A's) */ |
565 | Htaccess_IP *prev_IP = ip_a_d; | 594 | Htaccess_IP *prev_IP = ip_a_d; |
566 | if (prev_IP == NULL) { | 595 | if (prev_IP == NULL) { |
567 | ip_a_d = pip; | 596 | ip_a_d = pip; |
@@ -575,12 +604,12 @@ static void parse_conf(const char *path, int flag) | |||
575 | } | 604 | } |
576 | 605 | ||
577 | #if ENABLE_FEATURE_HTTPD_ERROR_PAGES | 606 | #if ENABLE_FEATURE_HTTPD_ERROR_PAGES |
578 | if (flag == FIRST_PARSE && *p0 == 'E') { | 607 | if (flag == FIRST_PARSE && ch == 'E') { |
579 | unsigned i; | 608 | unsigned i; |
580 | int status = atoi(++p0); /* error status code */ | 609 | int status = atoi(buf + 1); /* error status code */ |
610 | |||
581 | if (status < HTTP_CONTINUE) { | 611 | if (status < HTTP_CONTINUE) { |
582 | bb_error_msg("config error '%s' in '%s'", buf, filename); | 612 | goto config_error; |
583 | continue; | ||
584 | } | 613 | } |
585 | /* then error page; find matching status */ | 614 | /* then error page; find matching status */ |
586 | for (i = 0; i < ARRAY_SIZE(http_response_type); i++) { | 615 | for (i = 0; i < ARRAY_SIZE(http_response_type); i++) { |
@@ -597,7 +626,7 @@ static void parse_conf(const char *path, int flag) | |||
597 | #endif | 626 | #endif |
598 | 627 | ||
599 | #if ENABLE_FEATURE_HTTPD_PROXY | 628 | #if ENABLE_FEATURE_HTTPD_PROXY |
600 | if (flag == FIRST_PARSE && *p0 == 'P') { | 629 | if (flag == FIRST_PARSE && ch == 'P') { |
601 | /* P:/url:[http://]hostname[:port]/new/path */ | 630 | /* P:/url:[http://]hostname[:port]/new/path */ |
602 | char *url_from, *host_port, *url_to; | 631 | char *url_from, *host_port, *url_to; |
603 | Htaccess_Proxy *proxy_entry; | 632 | Htaccess_Proxy *proxy_entry; |
@@ -605,23 +634,20 @@ static void parse_conf(const char *path, int flag) | |||
605 | url_from = after_colon; | 634 | url_from = after_colon; |
606 | host_port = strchr(after_colon, ':'); | 635 | host_port = strchr(after_colon, ':'); |
607 | if (host_port == NULL) { | 636 | if (host_port == NULL) { |
608 | bb_error_msg("config error '%s' in '%s'", buf, filename); | 637 | goto config_error; |
609 | continue; | ||
610 | } | 638 | } |
611 | *host_port++ = '\0'; | 639 | *host_port++ = '\0'; |
612 | if (strncmp(host_port, "http://", 7) == 0) | 640 | if (strncmp(host_port, "http://", 7) == 0) |
613 | host_port += 7; | 641 | host_port += 7; |
614 | if (*host_port == '\0') { | 642 | if (*host_port == '\0') { |
615 | bb_error_msg("config error '%s' in '%s'", buf, filename); | 643 | goto config_error; |
616 | continue; | ||
617 | } | 644 | } |
618 | url_to = strchr(host_port, '/'); | 645 | url_to = strchr(host_port, '/'); |
619 | if (url_to == NULL) { | 646 | if (url_to == NULL) { |
620 | bb_error_msg("config error '%s' in '%s'", buf, filename); | 647 | goto config_error; |
621 | continue; | ||
622 | } | 648 | } |
623 | *url_to = '\0'; | 649 | *url_to = '\0'; |
624 | proxy_entry = xzalloc(sizeof(Htaccess_Proxy)); | 650 | proxy_entry = xzalloc(sizeof(*proxy_entry)); |
625 | proxy_entry->url_from = xstrdup(url_from); | 651 | proxy_entry->url_from = xstrdup(url_from); |
626 | proxy_entry->host_port = xstrdup(host_port); | 652 | proxy_entry->host_port = xstrdup(host_port); |
627 | *url_to = '/'; | 653 | *url_to = '/'; |
@@ -631,115 +657,87 @@ static void parse_conf(const char *path, int flag) | |||
631 | continue; | 657 | continue; |
632 | } | 658 | } |
633 | #endif | 659 | #endif |
660 | /* the rest of directives are non-alphabetic, | ||
661 | * must avoid using "toupper'ed" ch */ | ||
662 | ch = buf[0]; | ||
634 | 663 | ||
635 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH | 664 | if (ch == '.' /* ".ext:mime/type" */ |
636 | if (*p0 == '/') { | 665 | #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR |
637 | /* make full path from httpd root / current_path / config_line_path */ | 666 | || (ch == '*' && buf[1] == '.') /* "*.php:/path/php" */ |
638 | const char *tp = (flag == SUBDIR_PARSE ? path : ""); | 667 | #endif |
639 | p0 = xmalloc(strlen(tp) + (after_colon - buf) + 2 + strlen(after_colon)); | 668 | ) { |
640 | after_colon[-1] = '\0'; | 669 | char *p; |
641 | sprintf(p0, "/%s%s", tp, buf); | 670 | Htaccess *cur; |
642 | |||
643 | /* looks like bb_simplify_path... */ | ||
644 | tp = p = p0; | ||
645 | do { | ||
646 | if (*p == '/') { | ||
647 | if (*tp == '/') { /* skip duplicate (or initial) slash */ | ||
648 | continue; | ||
649 | } | ||
650 | if (*tp == '.') { | ||
651 | if (tp[1] == '/' || tp[1] == '\0') { /* remove extra '.' */ | ||
652 | continue; | ||
653 | } | ||
654 | if ((tp[1] == '.') && (tp[2] == '/' || tp[2] == '\0')) { | ||
655 | ++tp; | ||
656 | if (p > p0) { | ||
657 | while (*--p != '/') /* omit previous dir */ | ||
658 | continue; | ||
659 | } | ||
660 | continue; | ||
661 | } | ||
662 | } | ||
663 | } | ||
664 | *++p = *tp; | ||
665 | } while (*++tp); | ||
666 | 671 | ||
667 | if ((p == p0) || (*p != '/')) { /* not a trailing slash */ | 672 | cur = xzalloc(sizeof(*cur) /* includes space for NUL */ + strlen_buf); |
668 | ++p; /* so keep last character */ | 673 | strcpy(cur->before_colon, buf); |
674 | p = cur->before_colon + (after_colon - buf); | ||
675 | p[-1] = '\0'; | ||
676 | cur->after_colon = p; | ||
677 | if (ch == '.') { | ||
678 | /* .mime line: prepend to mime_a list */ | ||
679 | cur->next = mime_a; | ||
680 | mime_a = cur; | ||
681 | } | ||
682 | #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR | ||
683 | else { | ||
684 | /* script interpreter line: prepend to script_i list */ | ||
685 | cur->next = script_i; | ||
686 | script_i = cur; | ||
669 | } | 687 | } |
670 | *p = ':'; | ||
671 | strcpy(p + 1, after_colon); | ||
672 | } | ||
673 | #endif | 688 | #endif |
674 | if (*p0 == 'I') { | ||
675 | index_page = xstrdup(after_colon); | ||
676 | continue; | ||
677 | } | ||
678 | |||
679 | /* Do not allow jumping around using H in subdir's configs */ | ||
680 | if (flag == FIRST_PARSE && *p0 == 'H') { | ||
681 | home_httpd = xstrdup(after_colon); | ||
682 | xchdir(home_httpd); | ||
683 | continue; | 689 | continue; |
684 | } | 690 | } |
685 | 691 | ||
686 | /* storing current config line */ | ||
687 | cur = xzalloc(sizeof(Htaccess) + strlen(p0)); | ||
688 | strcpy(cur->before_colon, p0); | ||
689 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH | 692 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH |
690 | if (*p0 == '/') /* was malloced - see above */ | 693 | if (ch == '/') { /* "/file:user:pass" */ |
691 | free(p0); | 694 | char *p; |
692 | #endif | 695 | Htaccess *cur; |
693 | cur->after_colon = strchr(cur->before_colon, ':'); | 696 | unsigned file_len; |
694 | *cur->after_colon++ = '\0'; | 697 | |
695 | if (cur->before_colon[0] == '.') { | 698 | /* note: path is "" unless we are in SUBDIR parse, |
696 | /* .mime line: prepend to mime_a list */ | 699 | * otherwise it always starts with "/" */ |
697 | cur->next = mime_a; | 700 | cur = xzalloc(sizeof(*cur) /* includes space for NUL */ |
698 | mime_a = cur; | 701 | + strlen(path) |
699 | continue; | 702 | + strlen_buf |
700 | } | 703 | ); |
701 | #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR | 704 | /* form "/path/file" */ |
702 | if (cur->before_colon[0] == '*' && cur->before_colon[1] == '.') { | 705 | sprintf(cur->before_colon, "%s%.*s", |
703 | /* script interpreter line: prepend to script_i list */ | 706 | path, |
704 | cur->next = script_i; | 707 | after_colon - buf - 1, /* includes "/", but not ":" */ |
705 | script_i = cur; | 708 | buf); |
706 | continue; | 709 | /* canonicalize it */ |
707 | } | 710 | p = bb_simplify_abs_path_inplace(cur->before_colon); |
708 | #endif | 711 | file_len = p - cur->before_colon; |
709 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH | 712 | /* add "user:pass" after NUL */ |
710 | //TODO: we do not test for leading "/"?? | 713 | strcpy(++p, after_colon); |
711 | //also, do we leak cur if BASIC_AUTH is off? | 714 | cur->after_colon = p; |
712 | if (prev == NULL) { | 715 | |
713 | /* first line */ | 716 | /* insert cur into g_auth */ |
714 | g_auth = prev = cur; | 717 | /* g_auth is sorted by decreased filename length */ |
715 | } else { | 718 | { |
716 | /* sort path, if current length eq or bigger then move up */ | 719 | Htaccess *auth, **authp; |
717 | Htaccess *prev_hti = g_auth; | 720 | |
718 | size_t l = strlen(cur->before_colon); | 721 | authp = &g_auth; |
719 | Htaccess *hti; | 722 | while ((auth = *authp) != NULL) { |
720 | 723 | if (file_len >= strlen(auth->before_colon)) { | |
721 | for (hti = prev_hti; hti; hti = hti->next) { | 724 | /* insert cur before auth */ |
722 | if (l >= strlen(hti->before_colon)) { | 725 | cur->next = auth; |
723 | /* insert before hti */ | 726 | break; |
724 | cur->next = hti; | ||
725 | if (prev_hti != hti) { | ||
726 | prev_hti->next = cur; | ||
727 | } else { | ||
728 | /* insert as top */ | ||
729 | g_auth = cur; | ||
730 | } | 727 | } |
731 | break; | 728 | authp = &auth->next; |
732 | } | 729 | } |
733 | if (prev_hti != hti) | 730 | *authp = cur; |
734 | prev_hti = prev_hti->next; | ||
735 | } | ||
736 | if (!hti) { /* not inserted, add to bottom */ | ||
737 | prev->next = cur; | ||
738 | prev = cur; | ||
739 | } | 731 | } |
732 | continue; | ||
740 | } | 733 | } |
741 | #endif /* BASIC_AUTH */ | 734 | #endif /* BASIC_AUTH */ |
735 | |||
736 | /* the line is not recognized */ | ||
737 | config_error: | ||
738 | bb_error_msg("config error '%s' in '%s'", buf, filename); | ||
742 | } /* while (fgets) */ | 739 | } /* while (fgets) */ |
740 | |||
743 | fclose(f); | 741 | fclose(f); |
744 | } | 742 | } |
745 | 743 | ||
@@ -2031,8 +2029,8 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) | |||
2031 | /* We are done reading headers, disable peer timeout */ | 2029 | /* We are done reading headers, disable peer timeout */ |
2032 | alarm(0); | 2030 | alarm(0); |
2033 | 2031 | ||
2034 | if (strcmp(bb_basename(urlcopy), httpd_conf) == 0 || !ip_allowed) { | 2032 | if (strcmp(bb_basename(urlcopy), HTTPD_CONF) == 0 || !ip_allowed) { |
2035 | /* protect listing [/path]/httpd_conf or IP deny */ | 2033 | /* protect listing [/path]/httpd.conf or IP deny */ |
2036 | send_headers_and_exit(HTTP_FORBIDDEN); | 2034 | send_headers_and_exit(HTTP_FORBIDDEN); |
2037 | } | 2035 | } |
2038 | 2036 | ||
@@ -2245,7 +2243,7 @@ static void mini_httpd_inetd(void) | |||
2245 | 2243 | ||
2246 | static void sighup_handler(int sig UNUSED_PARAM) | 2244 | static void sighup_handler(int sig UNUSED_PARAM) |
2247 | { | 2245 | { |
2248 | parse_conf(default_path_httpd_conf, SIGNALED_PARSE); | 2246 | parse_conf(DEFAULT_PATH_HTTPD_CONF, SIGNALED_PARSE); |
2249 | } | 2247 | } |
2250 | 2248 | ||
2251 | enum { | 2249 | enum { |
@@ -2304,7 +2302,7 @@ int httpd_main(int argc UNUSED_PARAM, char **argv) | |||
2304 | IF_FEATURE_HTTPD_AUTH_MD5("m:") | 2302 | IF_FEATURE_HTTPD_AUTH_MD5("m:") |
2305 | IF_FEATURE_HTTPD_SETUID("u:") | 2303 | IF_FEATURE_HTTPD_SETUID("u:") |
2306 | "p:ifv", | 2304 | "p:ifv", |
2307 | &configFile, &url_for_decode, &home_httpd | 2305 | &opt_c_configFile, &url_for_decode, &home_httpd |
2308 | IF_FEATURE_HTTPD_ENCODE_URL_STR(, &url_for_encode) | 2306 | IF_FEATURE_HTTPD_ENCODE_URL_STR(, &url_for_encode) |
2309 | IF_FEATURE_HTTPD_BASIC_AUTH(, &g_realm) | 2307 | IF_FEATURE_HTTPD_BASIC_AUTH(, &g_realm) |
2310 | IF_FEATURE_HTTPD_AUTH_MD5(, &pass) | 2308 | IF_FEATURE_HTTPD_AUTH_MD5(, &pass) |
@@ -2375,7 +2373,7 @@ int httpd_main(int argc UNUSED_PARAM, char **argv) | |||
2375 | } | 2373 | } |
2376 | #endif | 2374 | #endif |
2377 | 2375 | ||
2378 | parse_conf(default_path_httpd_conf, FIRST_PARSE); | 2376 | parse_conf(DEFAULT_PATH_HTTPD_CONF, FIRST_PARSE); |
2379 | if (!(opt & OPT_INETD)) | 2377 | if (!(opt & OPT_INETD)) |
2380 | signal(SIGHUP, sighup_handler); | 2378 | signal(SIGHUP, sighup_handler); |
2381 | 2379 | ||