last_patch84 by Vodz.
No binary (build failed)
—
(log yok)
| @@ -42,7 +42,7 @@ | |
| * The server can also be invoked as a url arg decoder and html text encoder | |
| * as follows: | |
| * foo=`httpd -d $foo` # decode "Hello%20World" as "Hello World" | |
| - | * bar=`httpd -e "<Hello World>"` # encode as "%3CHello%20World%3E" |
| + | * bar=`httpd -e "<Hello World>"` # encode as "<Hello World>" |
| * | |
| * httpd.conf has the following format: | |
| @@ -56,51 +56,17 @@ D:* # Deny from other IP connections | |
| /adm:toor:PaSsWd # or user toor, pwd PaSsWd on urls starting with /adm/ | |
| .au:audio/basic # additional mime type for audio.au files | |
| - | A shortes path and D:from[^*] automaticaly sorting to top. |
| - | All longest path can`t reset user:password if shorted protect setted. |
| - | |
| A/D may be as a/d or allow/deny - first char case unsensitive parsed only. | |
| Each subdir can have config file. | |
| + | You can set less IP allow from subdir config. |
| + | Password protection from subdir config can rewriten previous sets for |
| + | current or/and next subpathes. |
| For protect as user:pass current subdir and subpathes set from subdir config: | |
| /:user:pass | |
| - | if not, other subpathes for give effect must have path from httpd root |
| - | /current_subdir_path_from_httpd_root/subpath:user:pass |
| - | |
| - | The Deny/Allow IP logic: |
| - | |
| - | 1. Allow all: |
| - | The config don`t set D: lines |
| - | |
| - | 2. Allow from setted only: |
| - | see the begin format example |
| - | |
| - | 3. Set deny, allow from other: |
| - | D:1.2.3. # deny from 1.2.3.0 - 1.2.3.255 |
| - | D:2.3.4. # deny from 2.3.4.0 - 2.3.4.255 |
| - | A:* # allow from other, this line not strongly require |
| - | |
| - | A global and subdirs config merging logic: |
| - | allow rules reducing, deny lines strongled. |
| - | The algorithm combinations: |
| - | |
| - | 4. If current config have |
| - | A:from |
| - | D:* |
| - | subdir config A: lines skiping, D:from - moving top |
| - | |
| - | 5. If current config have |
| - | D:from |
| - | A:* |
| - | result config: |
| - | D:from current |
| - | D:from subdir |
| - | A:from subdir |
| - | and seting D:* if subdir config have this |
| + | /subpath:user2:pass2 |
| If -c don`t setted, used httpd root config, else httpd root config skiped. | |
| - | Exited with fault if can`t open start config. |
| - | For set wide open server, use -c /dev/null ;=) |
| */ | |
| #include <stdio.h> | |
| @@ -120,30 +86,29 @@ A:from subdir | |
| #include "busybox.h" | |
| - | static const char httpdVersion[] = "busybox httpd/1.20 31-Jan-2003"; |
| - | static const char default_patch_httpd_conf[] = "/etc"; |
| + | static const char httpdVersion[] = "busybox httpd/1.25 10-May-2003"; |
| + | static const char default_path_httpd_conf[] = "/etc"; |
| static const char httpd_conf[] = "httpd.conf"; | |
| static const char home[] = "/www"; | |
| - | // Note: xfuncs are not used because we want the server to keep running |
| + | // Note: bussybox xfuncs are not used because we want the server to keep running |
| // if something bad happens due to a malformed user request. | |
| // As a result, all memory allocation after daemonize | |
| // is checked rigorously | |
| //#define DEBUG 1 | |
| - | /* Configure options, disabled by default as nonstandart httpd feature */ |
| + | /* Configure options, disabled by default as custom httpd feature */ |
| + | |
| + | /* disabled as optional features */ |
| //#define CONFIG_FEATURE_HTTPD_SET_CGI_VARS_TO_ENV | |
| //#define CONFIG_FEATURE_HTTPD_ENCODE_URL_STR | |
| - | //#define CONFIG_FEATURE_HTTPD_DECODE_URL_STR |
| - | |
| - | /* disabled as not necessary feature */ |
| //#define CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV | |
| //#define CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES | |
| //#define CONFIG_FEATURE_HTTPD_SETUID | |
| //#define CONFIG_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP | |
| - | /* If seted this you can use this server from internet superserver only */ |
| + | /* If set, use this server from internet superserver only */ |
| //#define CONFIG_FEATURE_HTTPD_USAGE_FROM_INETD_ONLY | |
| /* You can use this server as standalone, require libbb.a for linking */ | |
| @@ -160,7 +125,6 @@ static const char home[] = "/www"; | |
| #undef CONFIG_FEATURE_HTTPD_BASIC_AUTH | |
| #undef CONFIG_FEATURE_HTTPD_SET_CGI_VARS_TO_ENV | |
| #undef CONFIG_FEATURE_HTTPD_ENCODE_URL_STR | |
| - | #undef CONFIG_FEATURE_HTTPD_DECODE_URL_STR |
| #undef CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV | |
| #undef CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES | |
| #undef CONFIG_FEATURE_HTTPD_CGI | |
| @@ -170,7 +134,6 @@ static const char home[] = "/www"; | |
| #define CONFIG_FEATURE_HTTPD_BASIC_AUTH | |
| #define CONFIG_FEATURE_HTTPD_SET_CGI_VARS_TO_ENV | |
| #define CONFIG_FEATURE_HTTPD_ENCODE_URL_STR | |
| - | #define CONFIG_FEATURE_HTTPD_DECODE_URL_STR |
| #define CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV | |
| #define CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES | |
| #define CONFIG_FEATURE_HTTPD_CGI | |
| @@ -183,7 +146,7 @@ const char *bb_applet_name = "httpd"; | |
| void bb_show_usage(void) | |
| { | |
| fprintf(stderr, "Usage: %s [-p <port>] [-c configFile] [-d/-e <string>] " | |
| - | "[-r realm] [-u user]\n", bb_applet_name); |
| + | "[-r realm] [-u user] [-h homedir]\n", bb_applet_name); |
| exit(1); | |
| } | |
| #endif | |
| @@ -232,6 +195,15 @@ typedef struct | |
| const char *found_mime_type; | |
| off_t ContentLength; /* -1 - unknown */ | |
| time_t last_mod; | |
| + | |
| + | Htaccess *ip_a_d; /* config allow/deny lines */ |
| + | #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH |
| + | Htaccess *auth; /* config user:password lines */ |
| + | #endif |
| + | #ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES |
| + | Htaccess *mime_a; /* config mime types */ |
| + | #endif |
| + | |
| #ifndef CONFIG_FEATURE_HTTPD_USAGE_FROM_INETD_ONLY | |
| int accepted_socket; | |
| #define a_c_r config->accepted_socket | |
| @@ -241,7 +213,6 @@ typedef struct | |
| #define a_c_r 0 | |
| #define a_c_w 1 | |
| #endif | |
| - | Htaccess *Httpd_conf_parsed; |
| } HttpdConfig; | |
| static HttpdConfig *config; | |
| @@ -308,15 +279,16 @@ static const HttpEnumString httpResponseNames[] = { | |
| { HTTP_OK, "OK" }, | |
| { HTTP_NOT_IMPLEMENTED, "Not Implemented", | |
| "The requested method is not recognized by this server." }, | |
| + | #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH |
| { HTTP_UNAUTHORIZED, "Unauthorized", "" }, | |
| + | #endif |
| { HTTP_NOT_FOUND, "Not Found", | |
| "The requested URL was not found on this server." }, | |
| - | { HTTP_BAD_REQUEST, "Bad Request" , |
| - | "Unsupported method." }, |
| + | { HTTP_BAD_REQUEST, "Bad Request", "Unsupported method." }, |
| { HTTP_FORBIDDEN, "Forbidden", "" }, | |
| - | { HTTP_INTERNAL_SERVER_ERROR, "Internal Server Error" |
| + | { HTTP_INTERNAL_SERVER_ERROR, "Internal Server Error", |
| "Internal Server Error" }, | |
| - | #if 0 |
| + | #if 0 /* not implemented */ |
| { HTTP_CREATED, "Created" }, | |
| { HTTP_ACCEPTED, "Accepted" }, | |
| { HTTP_NO_CONTENT, "No Content" }, | |
| @@ -334,157 +306,106 @@ static const char RFC1123FMT[] = "%a, %d %b %Y %H:%M:%S GMT"; | |
| static const char Content_length[] = "Content-length:"; | |
| - | /* |
| - | * sotring to: |
| - | * .ext:mime/type |
| - | * /path:user:pass |
| - | * /path/subdir:user:pass |
| - | * D:from |
| - | * A:from |
| - | * D:* |
| - | */ |
| - | static int conf_sort(const void *p1, const void *p2) |
| + | |
| + | static void free_config_lines(Htaccess **pprev) |
| { | |
| - | const Htaccess *cl1 = *(const Htaccess **)p1; |
| - | const Htaccess *cl2 = *(const Htaccess **)p2; |
| - | char c1 = cl1->before_colon[0]; |
| - | char c2 = cl2->before_colon[0]; |
| - | int test; |
| + | Htaccess *prev = *pprev; |
| - | #ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES |
| - | /* .ext line up before other lines for simlify algorithm */ |
| - | test = c2 == '.'; |
| - | if(c1 == '.') |
| - | return -(!test); |
| - | if(test) |
| - | return test; |
| - | #endif |
| + | while( prev ) { |
| + | Htaccess *cur = prev; |
| - | #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH |
| - | test = c1 == '/'; |
| - | /* /path line up before A/D lines for simlify algorithm */ |
| - | if(test) { |
| - | if(c2 != '/') |
| - | return -test; |
| - | /* a shortes path with user:pass must be first */ |
| - | return strlen(cl1->before_colon) - strlen(cl2->before_colon); |
| - | } else if(c2 == '/') |
| - | return !test; |
| - | #endif |
| - | |
| - | /* D:from must move top */ |
| - | test = c2 == 'D' && cl2->after_colon[0] != 0; |
| - | if(c1 == 'D' && cl1->after_colon[0] != 0) { |
| - | return -(!test); |
| + | prev = cur->next; |
| + | free(cur); |
| } | |
| - | if(test) |
| - | return test; |
| + | *pprev = NULL; |
| + | } |
| - | /* next lines - A:from */ |
| - | test = c2 == 'A' && cl2->after_colon[0] != 0; |
| - | if(c1 == 'A' && cl1->after_colon[0] != 0) { |
| - | return -(!test); |
| - | } |
| - | if(test) |
| - | return test; |
| + | static void add_config_line(Htaccess **pprev, Htaccess *cur) |
| + | { |
| + | if(*pprev == NULL) { |
| + | *pprev = cur; |
| + | } else { |
| + | Htaccess *prev; |
| - | /* end lines - D:* */ |
| - | test = c2 == 'D' && cl2->after_colon[0] == 0; |
| - | if(c1 == 'D' && cl1->after_colon[0] == 0) { |
| - | return -(!test); |
| + | for(prev = *pprev; prev->next; prev = prev->next) |
| + | ; |
| + | prev->next = cur; |
| } | |
| - | #ifdef DEBUG |
| - | if(!test) |
| - | bb_error_msg_and_die("sort: can`t found compares!"); |
| - | #endif |
| - | return test; |
| } | |
| - | |
| /* flag */ | |
| - | #define FIRST_PARSE 0 |
| - | #define SUBDIR_PARSE 1 |
| - | #define SIGNALED_PARSE 2 |
| + | #define FIRST_PARSE 0 |
| + | #define SUBDIR_PARSE 1 |
| + | #define SIGNALED_PARSE 2 |
| + | #define FIND_FROM_HTTPD_ROOT 3 |
| static void parse_conf(const char *path, int flag) | |
| { | |
| - | #define bc cur->before_colon[0] |
| - | #define ac cur->after_colon[0] |
| FILE *f; | |
| - | Htaccess *prev; |
| Htaccess *cur; | |
| + | #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH |
| + | Htaccess *prev; |
| + | #endif |
| + | |
| const char *cf = config->configFile; | |
| char buf[80]; | |
| char *p0 = NULL; | |
| - | int deny_all = 0; /* default A:* */ |
| - | int n = 0; /* count config lines */ |
| + | char *c, *p; |
| + | |
| + | /* free previous setuped */ |
| + | free_config_lines(&config->ip_a_d); |
| + | if(flag != SUBDIR_PARSE) { |
| + | #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH |
| + | free_config_lines(&config->auth) |
| + | #endif |
| + | ; /* syntax confuse */ |
| + | #ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES |
| + | free_config_lines(&config->mime_a); |
| + | #endif |
| + | } |
| if(flag == SUBDIR_PARSE || cf == NULL) { | |
| - | cf = p0 = alloca(strlen(path) + sizeof(httpd_conf) + 2); |
| - | if(p0 == NULL) { |
| + | cf = alloca(strlen(path) + sizeof(httpd_conf) + 2); |
| + | if(cf == NULL) { |
| if(flag == FIRST_PARSE) | |
| bb_error_msg_and_die(bb_msg_memory_exhausted); | |
| return; | |
| } | |
| - | sprintf(p0, "%s/%s", path, httpd_conf); |
| + | sprintf((char *)cf, "%s/%s", path, httpd_conf); |
| } | |
| while((f = fopen(cf, "r")) == NULL) { | |
| - | if(flag != FIRST_PARSE) |
| - | return; /* subdir config not found */ |
| - | if(p0 == NULL) /* if -c option gived */ |
| - | bb_perror_msg_and_die("%s", cf); |
| - | p0 = NULL; |
| - | cf = httpd_conf; /* set -c ./httpd_conf */ |
| - | } |
| - | |
| - | prev = config->Httpd_conf_parsed; |
| - | if(flag != SUBDIR_PARSE) { |
| - | /* free previous setuped */ |
| - | while( prev ) { |
| - | cur = prev; |
| - | prev = cur->next; |
| - | free(cur); |
| - | } |
| - | config->Httpd_conf_parsed = prev; /* eq NULL */ |
| - | } else { |
| - | /* parse previous IP logic for merge */ |
| - | for(cur = prev; cur; cur = cur->next) { |
| - | if(bc == 'D' && ac == 0) |
| - | deny_all++; |
| - | n++; |
| - | /* find last for set prev->next of merging */ |
| - | if(cur != prev) |
| - | prev = prev->next; |
| + | if(flag != FIRST_PARSE) { |
| + | /* config file not found */ |
| + | return; |
| } | |
| + | if(config->configFile) /* if -c option given */ |
| + | bb_perror_msg_and_die("%s", cf); |
| + | flag = FIND_FROM_HTTPD_ROOT; |
| + | cf = httpd_conf; |
| } | |
| - | /* This could stand some work */ |
| + | #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH |
| + | prev = config->auth; |
| + | #endif |
| + | /* This could stand some work */ |
| while ( (p0 = fgets(buf, 80, f)) != NULL) { | |
| - | char *p; |
| - | char *colon; |
| - | |
| - | for(p = colon = p0; *p; p++) { |
| - | if(*p == '#') { |
| - | *p = 0; |
| - | break; |
| + | c = NULL; |
| + | for(p = p0; *p0 != 0 && *p0 != '#'; p0++) { |
| + | if(!isspace(*p0)) { |
| + | *p++ = *p0; |
| + | if(*p0 == ':' && c == NULL) |
| + | c = p; |
| } | |
| - | if(isspace(*p)) { |
| - | if(p != p0) { |
| - | *p = 0; |
| - | break; |
| - | } |
| - | p0++; |
| - | } |
| - | else if(*p == ':' && colon <= p0) |
| - | colon = p; |
| } | |
| + | *p = 0; |
| /* test for empty or strange line */ | |
| - | if (colon <= p0 || colon[1] == 0) |
| + | if (c == NULL || *c == 0) |
| continue; | |
| - | if(colon[1] == '*') |
| - | colon[1] = 0; /* Allow all */ |
| + | if(*c == '*') |
| + | *c = 0; /* Allow all */ |
| + | p0 = buf; |
| if(*p0 == 'a') | |
| *p0 = 'A'; | |
| if(*p0 == 'd') | |
| @@ -498,70 +419,109 @@ static void parse_conf(const char *path, int flag) | |
| #endif | |
| ) | |
| continue; | |
| - | #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH |
| - | if(*p0 == '/' && colon[1] == 0) { |
| - | /* skip /path:* */ |
| + | |
| + | if(*p0 == 'A' && *c == 0) { |
| + | /* skip default A:* */ |
| continue; | |
| } | |
| - | #endif |
| + | p0 = buf; |
| + | #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH |
| + | if(*p0 == '/') { |
| + | if(*c == 0) { |
| + | /* skip /path:* */ |
| + | continue; |
| + | } |
| + | /* make full path from httpd root / curent_path / config_line_path */ |
| + | cf = flag == SUBDIR_PARSE ? path : ""; |
| + | p0 = malloc(strlen(cf) + (c - buf) + 2 + strlen(c)); |
| + | if(p0 == NULL) |
| + | continue; |
| + | c[-1] = 0; |
| + | sprintf(p0, "/%s%s", cf, buf); |
| + | |
| + | /* another call bb_simplify_path */ |
| + | cf = p = p0; |
| + | |
| + | do { |
| + | if (*p == '/') { |
| + | if (*cf == '/') { /* skip duplicate (or initial) slash */ |
| + | continue; |
| + | } else if (*cf == '.') { |
| + | if (cf[1] == '/' || cf[1] == 0) { /* remove extra '.' */ |
| + | continue; |
| + | } else if ((cf[1] == '.') && (cf[2] == '/' || cf[2] == 0)) { |
| + | ++cf; |
| + | if (p > p0) { |
| + | while (*--p != '/'); /* omit previous dir */ |
| + | } |
| + | continue; |
| + | } |
| + | } |
| + | } |
| + | *++p = *cf; |
| + | } while (*++cf); |
| - | if(*p0 == 'A' || *p0 == 'D') { |
| - | if(colon[1] == 0) { |
| - | if(*p0 == 'A' || deny_all != 0) |
| - | continue; /* skip default A:* or double D:* */ |
| + | if ((p == p0) || (*p != '/')) { /* not a trailing slash */ |
| + | ++p; /* so keep last character */ |
| } | |
| - | if(deny_all != 0 && *p0 == 'A') |
| - | continue; // if previous setted rule D:* skip all subdir A: |
| + | *p = 0; |
| + | sprintf(p0, "%s:%s", p0, c); |
| } | |
| - | |
| + | #endif |
| /* storing current config line */ | |
| - | cur = calloc(1, sizeof(Htaccess) + (p-p0)); |
| + | |
| + | cur = calloc(1, sizeof(Htaccess) + strlen(p0)); |
| if(cur) { | |
| - | if(*(colon-1) == '/' && (colon-1) != p0) |
| - | colon[-1] = 0; // remove last / from /path/ |
| - | cur->after_colon = strcpy(cur->before_colon, p0); |
| - | cur->after_colon += (colon-p0); |
| - | *cur->after_colon++ = 0; |
| + | cf = strcpy(cur->before_colon, p0); |
| + | c = strchr(cf, ':'); |
| + | *c++ = 0; |
| + | cur->after_colon = c; |
| + | #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH |
| + | if(*cf == '/') |
| + | free(p0); |
| + | #endif |
| + | if(*cf == 'A' || *cf == 'D') |
| + | add_config_line(&config->ip_a_d, cur); |
| + | #ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES |
| + | else if(*cf == '.') |
| + | add_config_line(&config->mime_a, cur); |
| + | #endif |
| - | if(prev == NULL) { |
| + | #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH |
| + | else if(prev == NULL) { |
| /* first line */ | |
| - | config->Httpd_conf_parsed = prev = cur; |
| + | config->auth = prev = cur; |
| } else { | |
| - | prev->next = cur; |
| - | prev = cur; |
| + | /* sort path, if current lenght eq or bigger then move up */ |
| + | Htaccess *prev_hti = config->auth; |
| + | int l = strlen(cf); |
| + | Htaccess *hti; |
| + | |
| + | for(hti = prev_hti; hti; hti = hti->next) { |
| + | if(l >= strlen(hti->before_colon)) { |
| + | /* insert before hti */ |
| + | cur->next = hti; |
| + | if(prev_hti != hti) { |
| + | prev_hti->next = cur; |
| + | break; |
| + | } else { |
| + | /* insert as top */ |
| + | config->auth = cur; |
| + | break; |
| + | } |
| + | } |
| + | if(prev_hti != hti) |
| + | prev_hti = prev_hti->next; |
| + | } |
| + | if(!hti) { /* not inserted, add to bottom */ |
| + | prev->next = cur; |
| + | prev = cur; |
| + | } |
| } | |
| - | n++; |
| + | #endif |
| } | |
| } | |
| fclose(f); | |
| - | |
| - | if(n > 1) { |
| - | /* sorting conf lines */ |
| - | Htaccess ** pcur; /* array for qsort */ |
| - | |
| - | prev = config->Httpd_conf_parsed; |
| - | pcur = alloca((n + 1) * sizeof(Htaccess *)); |
| - | if(pcur == NULL) { |
| - | if(flag == FIRST_PARSE) |
| - | bb_error_msg_and_die(bb_msg_memory_exhausted); |
| - | return; |
| - | } |
| - | n = 0; |
| - | for(cur = prev; cur; cur = cur->next) |
| - | pcur[n++] = cur; |
| - | pcur[n] = NULL; |
| - | |
| - | qsort(pcur, n, sizeof(Htaccess *), conf_sort); |
| - | |
| - | /* storing sorted config */ |
| - | config->Httpd_conf_parsed = *pcur; |
| - | for(cur = *pcur; cur; cur = cur->next) { |
| - | #ifdef DEBUG |
| - | bb_error_msg("%s: %s:%s", cf, cur->before_colon, cur->after_colon); |
| - | #endif |
| - | cur->next = *++pcur; |
| - | } |
| - | } |
| } | |
| #ifdef CONFIG_FEATURE_HTTPD_ENCODE_URL_STR | |
| @@ -602,7 +562,6 @@ static char *encodeString(const char *string) | |
| } | |
| #endif /* CONFIG_FEATURE_HTTPD_ENCODE_URL_STR */ | |
| - | #ifdef CONFIG_FEATURE_HTTPD_DECODE_URL_STR |
| /**************************************************************************** | |
| * | |
| > $Function: decodeString() | |
| @@ -615,20 +574,21 @@ static char *encodeString(const char *string) | |
| * | |
| * $Parameters: | |
| * (char *) string . . . The first string to decode. | |
| + | * (int) flag . . . 1 if require decode '+' as ' ' for CGI |
| * | |
| * $Return: (char *) . . . . A pointer to the decoded string (same as input). | |
| * | |
| * $Errors: None | |
| * | |
| ****************************************************************************/ | |
| - | static char *decodeString(char *string) |
| + | static char *decodeString(char *string, int flag_plus_to_space) |
| { | |
| /* note that decoded string is always shorter than original */ | |
| char *orig = string; | |
| char *ptr = string; | |
| while (*ptr) | |
| { | |
| - | if (*ptr == '+') { *string++ = ' '; ptr++; } |
| + | if (*ptr == '+' && flag_plus_to_space) { *string++ = ' '; ptr++; } |
| else if (*ptr != '%') *string++ = *ptr++; | |
| else { | |
| unsigned int value; | |
| @@ -640,7 +600,6 @@ static char *decodeString(char *string) | |
| *string = '\0'; | |
| return orig; | |
| } | |
| - | #endif /* CONFIG_FEATURE_HTTPD_DECODE_URL_STR */ |
| #ifdef CONFIG_FEATURE_HTTPD_CGI | |
| @@ -730,7 +689,7 @@ static void addEnvCgi(const char *pargs) | |
| args = strchr(value, '&'); | |
| if (args) | |
| *args++ = 0; | |
| - | addEnv("CGI", name, decodeString(value)); |
| + | addEnv("CGI", name, decodeString(value, 1)); |
| } | |
| free(memargs); | |
| } | |
| @@ -758,33 +717,44 @@ static void addEnvCgi(const char *pargs) | |
| ****************************************************************************/ | |
| static void decodeBase64(char *Data) | |
| { | |
| - | int i = 0; |
| - | static const char base64ToBin[] = |
| - | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
| const unsigned char *in = Data; | |
| // The decoded size will be at most 3/4 the size of the encoded | |
| unsigned long ch = 0; | |
| + | int i = 0; |
| while (*in) { | |
| - | unsigned char conv = 0; |
| - | |
| - | while (*in) { |
| - | const char *p64; |
| + | int t = *in++; |
| - | p64 = strchr(base64ToBin, *in++); |
| - | if(p64 == NULL) |
| - | continue; |
| - | conv = (p64 - base64ToBin); |
| - | break; |
| + | switch(t) { |
| + | case '+': |
| + | t = 62; |
| + | break; |
| + | case '/': |
| + | t = 63; |
| + | break; |
| + | case '=': |
| + | t = 0; |
| + | break; |
| + | case 'A' ... 'Z': |
| + | t = t - 'A'; |
| + | break; |
| + | case 'a' ... 'z': |
| + | t = t - 'a' + 26; |
| + | break; |
| + | case '0' ... '9': |
| + | t = t - '0' + 52; |
| + | break; |
| + | default: |
| + | continue; |
| } | |
| - | ch = (ch << 6) | conv; |
| + | ch = (ch << 6) | t; |
| i++; | |
| - | if (i== 4) { |
| - | *Data++ = (char) (ch >> 16); |
| - | *Data++ = (char) (ch >> 8); |
| - | *Data++ = (char) ch; |
| - | i = 0; |
| + | if (i == 4) { |
| + | *Data++ = (char) (ch >> 16); |
| + | *Data++ = (char) (ch >> 8); |
| + | *Data++ = (char) ch; |
| + | i = 0; |
| } | |
| } | |
| *Data = 0; | |
| @@ -1203,7 +1173,7 @@ static int sendFile(const char *url, char *buf) | |
| if (suffix) { | |
| Htaccess * cur; | |
| - | for (cur = config->Httpd_conf_parsed; cur; cur = cur->next) { |
| + | for (cur = config->mime_a; cur; cur = cur->next) { |
| if(strcmp(cur->before_colon, suffix) == 0) { | |
| config->found_mime_type = cur->after_colon; | |
| break; | |
| @@ -1255,74 +1225,71 @@ static int sendFile(const char *url, char *buf) | |
| * | |
| ****************************************************************************/ | |
| - | |
| + | #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH |
| static int checkPerm(const char *path, const char *request) | |
| { | |
| Htaccess * cur; | |
| const char *p; | |
| + | const char *p0; |
| - | #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH |
| int ipaddr = path == NULL; | |
| const char *prev = NULL; | |
| - | #else |
| - | # define ipaddr 1 |
| - | #endif |
| /* This could stand some work */ | |
| - | for (cur = config->Httpd_conf_parsed; cur; cur = cur->next) { |
| - | const char *p0 = cur->before_colon; |
| - | |
| - | if(*p0 == 'A' || *p0 == 'D') { |
| - | if(!ipaddr) |
| - | continue; |
| - | } else { |
| - | if(ipaddr) |
| - | continue; |
| - | #ifdef CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES |
| - | if(*p0 == '.') |
| - | continue; |
| - | #endif |
| - | #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH |
| - | if(prev != NULL && strcmp(prev, p0) != 0) |
| - | continue; /* find next identical */ |
| - | #endif |
| - | } |
| - | |
| + | for (cur = ipaddr ? config->ip_a_d : config->auth; cur; cur = cur->next) { |
| + | p0 = cur->before_colon; |
| + | if(prev != NULL && strcmp(prev, p0) != 0) |
| + | continue; /* find next identical */ |
| p = cur->after_colon; | |
| #ifdef DEBUG | |
| if (config->debugHttpd) | |
| - | fprintf(stderr,"checkPerm: '%s' ? '%s'\n", |
| - | (ipaddr ? p : p0), request); |
| + | fprintf(stderr,"checkPerm: '%s' ? '%s'\n", |
| + | (ipaddr ? (*p ? p : "*") : p0), request); |
| #endif | |
| if(ipaddr) { | |
| - | if(strncmp(p, request, strlen(p)) != 0) |
| - | continue; |
| - | return *p0 == 'A'; /* Allow/Deny */ |
| - | |
| + | if(strncmp(p, request, strlen(p)) != 0) |
| + | continue; |
| + | return *p0 == 'A'; /* Allow/Deny */ |
| + | } else { |
| + | int l = strlen(p0); |
| + | |
| + | if(strncmp(p0, path, l) == 0 && |
| + | (l == 1 || path[l] == '/' || path[l] == 0)) { |
| + | /* path match found. Check request */ |
| + | if (strcmp(p, request) == 0) |
| + | return 1; /* Ok */ |
| + | /* unauthorized, but check next /path:user:password */ |
| + | prev = p0; |
| + | } |
| } | |
| - | #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH |
| - | else { |
| - | int l = strlen(p0); |
| - | |
| - | if(strncmp(p0, path, l) == 0 && |
| - | (l == 1 || path[l] == '/' || path[l] == 0)) { |
| - | /* path match found. Check request */ |
| - | if (strcmp(p, request) == 0) |
| - | return 1; /* Ok */ |
| - | /* unauthorized, but check next /path:user:password */ |
| - | prev = p0; |
| - | } |
| - | } |
| - | #endif |
| } /* for */ | |
| - | #ifndef CONFIG_FEATURE_HTTPD_BASIC_AUTH |
| - | /* if uncofigured, return 1 - access from all */ |
| - | return 1; |
| - | #else |
| return prev == NULL; | |
| + | } |
| + | |
| + | #else /* ifndef CONFIG_FEATURE_HTTPD_BASIC_AUTH */ |
| + | static int checkPermIP(const char *request) |
| + | { |
| + | Htaccess * cur; |
| + | const char *p; |
| + | |
| + | /* This could stand some work */ |
| + | for (cur = config->ip_a_d; cur; cur = cur->next) { |
| + | p = cur->after_colon; |
| + | #ifdef DEBUG |
| + | if (config->debugHttpd) |
| + | fprintf(stderr, "checkPerm: '%s' ? '%s'\n", |
| + | (*p ? p : "*"), request); |
| #endif | |
| + | if(strncmp(p, request, strlen(p)) == 0) |
| + | return *cur->before_colon == 'A'; /* Allow/Deny */ |
| + | } |
| + | |
| + | /* if uncofigured, return 1 - access from all */ |
| + | return 1; |
| } | |
| + | #define checkPerm(null, request) checkPermIP(request) |
| + | #endif /* CONFIG_FEATURE_HTTPD_BASIC_AUTH */ |
| /**************************************************************************** | |
| @@ -1347,6 +1314,7 @@ static void handleIncoming(void) | |
| #endif | |
| char *test; | |
| struct stat sb; | |
| + | int ip_allowed; |
| #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH | |
| int credentials = -1; /* if not requred this is Ok */ | |
| @@ -1382,6 +1350,7 @@ BAD_REQUEST: | |
| *purl = ' '; | |
| count = sscanf(purl, " %[^ ] HTTP/%d.%*d", buf, &blank); | |
| + | decodeString(buf, 0); |
| if (count < 1 || buf[0] != '/') { | |
| /* Garbled request/URL */ | |
| goto BAD_REQUEST; | |
| @@ -1394,13 +1363,11 @@ BAD_REQUEST: | |
| strcpy(url, buf); | |
| /* extract url args if present */ | |
| urlArgs = strchr(url, '?'); | |
| - | if (urlArgs) { |
| - | *urlArgs++ = 0; /* next code can set '/' to this pointer, |
| - | but CGI script can`t be a directory */ |
| - | } |
| + | if (urlArgs) |
| + | *urlArgs++ = 0; |
| /* algorithm stolen from libbb bb_simplify_path(), | |
| - | but don`t strdup and reducing trailing slash */ |
| + | but don`t strdup and reducing trailing slash and protect out root */ |
| purl = test = url; | |
| do { | |
| @@ -1441,12 +1408,14 @@ BAD_REQUEST: | |
| #endif | |
| test = url; | |
| - | while((test = strchr( test + 1, '/' )) != NULL) { |
| + | ip_allowed = checkPerm(NULL, config->rmt_ip); |
| + | while(ip_allowed && (test = strchr( test + 1, '/' )) != NULL) { |
| /* have path1/path2 */ | |
| *test = '\0'; | |
| if( is_directory(url + 1, 1, &sb) ) { | |
| /* may be having subdir config */ | |
| parse_conf(url + 1, SUBDIR_PARSE); | |
| + | ip_allowed = checkPerm(NULL, config->rmt_ip); |
| } | |
| *test = '/'; | |
| } | |
| @@ -1490,8 +1459,7 @@ BAD_REQUEST: | |
| } /* while extra header reading */ | |
| - | if (strcmp(strrchr(url, '/') + 1, httpd_conf) == 0 || |
| - | checkPerm(NULL, config->rmt_ip) == 0) { |
| + | if (strcmp(strrchr(url, '/') + 1, httpd_conf) == 0 || ip_allowed == 0) { |
| /* protect listing [/path]/httpd_conf or IP deny */ | |
| #ifdef CONFIG_FEATURE_HTTPD_CGI | |
| FORBIDDEN: /* protect listing /cgi-bin */ | |
| @@ -1525,8 +1493,8 @@ FORBIDDEN: /* protect listing /cgi-bin */ | |
| } | |
| if (strncmp(test, "cgi-bin", 7) == 0) { | |
| - | if(test[7] == 0 || (test[7] == '/' && test[8] == 0)) |
| - | goto FORBIDDEN; // protect listing cgi-bin |
| + | if(test[7] == '/' && test[8] == 0) |
| + | goto FORBIDDEN; // protect listing cgi-bin/ |
| sendCgi(url, prequest, urlArgs, body, length, cookie); | |
| } else { | |
| if (prequest != request_GET) | |
| @@ -1587,7 +1555,6 @@ FORBIDDEN: /* protect listing /cgi-bin */ | |
| static int miniHttpd(int server) | |
| { | |
| fd_set readfd, portfd; | |
| - | int nfound; |
| FD_ZERO(&portfd); | |
| FD_SET(server, &portfd); | |
| @@ -1597,16 +1564,7 @@ static int miniHttpd(int server) | |
| readfd = portfd; | |
| /* Now wait INDEFINATELY on the set of sockets! */ | |
| - | nfound = select(server + 1, &readfd, 0, 0, 0); |
| - | |
| - | switch (nfound) { |
| - | case 0: |
| - | /* select timeout error! */ |
| - | break ; |
| - | case -1: |
| - | /* select error */ |
| - | break; |
| - | default: |
| + | if (select(server + 1, &readfd, 0, 0, 0) > 0) { |
| if (FD_ISSET(server, &readfd)) { | |
| int on; | |
| struct sockaddr_in fromAddr; | |
| @@ -1617,7 +1575,7 @@ static int miniHttpd(int server) | |
| (struct sockaddr *)&fromAddr, &fromAddrLen); | |
| if (s < 0) { | |
| - | continue; |
| + | continue; |
| } | |
| config->accepted_socket = s; | |
| addr = ntohl(fromAddr.sin_addr.s_addr); | |
| @@ -1629,7 +1587,7 @@ static int miniHttpd(int server) | |
| config->port = ntohs(fromAddr.sin_port); | |
| #ifdef DEBUG | |
| if (config->debugHttpd) { | |
| - | bb_error_msg("connection from IP=%s, port %u\n", |
| + | bb_error_msg("connection from IP=%s, port %u\n", |
| config->rmt_ip, config->port); | |
| } | |
| #endif | |
| @@ -1638,9 +1596,13 @@ static int miniHttpd(int server) | |
| setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof (on)); | |
| if (config->debugHttpd || fork() == 0) { | |
| - | /* This is the spawned thread */ |
| - | handleIncoming(); |
| - | if(!config->debugHttpd) |
| + | /* This is the spawned thread */ |
| + | #ifdef CONFIG_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP |
| + | /* protect reload config, may be confuse checking */ |
| + | signal(SIGHUP, SIG_IGN); |
| + | #endif |
| + | handleIncoming(); |
| + | if(!config->debugHttpd) |
| exit(0); | |
| } | |
| close(s); | |
| @@ -1682,7 +1644,7 @@ static void sighup_handler(int sig) | |
| sigemptyset(&sa.sa_mask); | |
| sa.sa_flags = SA_RESTART; | |
| sigaction(SIGHUP, &sa, NULL); | |
| - | parse_conf(default_patch_httpd_conf, |
| + | parse_conf(default_path_httpd_conf, |
| sig == SIGHUP ? SIGNALED_PARSE : FIRST_PARSE); | |
| } | |
| #endif | |
| @@ -1716,16 +1678,13 @@ int httpd_main(int argc, char *argv[]) | |
| /* check if user supplied a port number */ | |
| for (;;) { | |
| - | int c = getopt( argc, argv, "c:h:" |
| + | int c = getopt( argc, argv, "c:d:h:" |
| #ifndef CONFIG_FEATURE_HTTPD_USAGE_FROM_INETD_ONLY | |
| "p:v" | |
| #endif | |
| #ifdef CONFIG_FEATURE_HTTPD_ENCODE_URL_STR | |
| "e:" | |
| #endif | |
| - | #ifdef CONFIG_FEATURE_HTTPD_DECODE_URL_STR |
| - | "d:" |
| - | #endif |
| #ifdef CONFIG_FEATURE_HTTPD_BASIC_AUTH | |
| "r:" | |
| #endif | |
| @@ -1751,11 +1710,9 @@ int httpd_main(int argc, char *argv[]) | |
| bb_error_msg_and_die("invalid %s for -p", optarg); | |
| break; | |
| #endif | |
| - | #ifdef CONFIG_FEATURE_HTTPD_DECODE_URL_STR |
| case 'd': | |
| - | printf("%s", decodeString(optarg)); |
| + | printf("%s", decodeString(optarg, 1)); |
| return 0; | |
| - | #endif |
| #ifdef CONFIG_FEATURE_HTTPD_ENCODE_URL_STR | |
| case 'e': | |
| printf("%s", encodeString(optarg)); | |
| @@ -1803,7 +1760,7 @@ int httpd_main(int argc, char *argv[]) | |
| #ifdef CONFIG_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP | |
| sighup_handler(0); | |
| #else | |
| - | parse_conf(default_patch_httpd_conf, FIRST_PARSE); |
| + | parse_conf(default_path_httpd_conf, FIRST_PARSE); |
| #endif | |
| #ifndef CONFIG_FEATURE_HTTPD_USAGE_FROM_INETD_ONLY | |