From: Jo-Philipp Wich Date: Wed, 11 Aug 2010 00:23:13 +0000 (+0000) Subject: [backfire] merge r22589 X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=5c7cceca0a6354c2dddbf788f6651f2699e88a2c;p=openwrt%2Fsvn-archive%2Farchive.git [backfire] merge r22589 SVN-Revision: 22590 --- diff --git a/package/uhttpd/Makefile b/package/uhttpd/Makefile index eb4238c904..8a7b5295d9 100644 --- a/package/uhttpd/Makefile +++ b/package/uhttpd/Makefile @@ -8,9 +8,10 @@ include $(TOPDIR)/rules.mk PKG_NAME:=uhttpd -PKG_RELEASE:=11 +PKG_RELEASE:=13 PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) +PKG_BUILD_DEPENDS := libcyassl liblua include $(INCLUDE_DIR)/package.mk diff --git a/package/uhttpd/files/uhttpd.config b/package/uhttpd/files/uhttpd.config index acdd62ea4e..534e8f8b29 100644 --- a/package/uhttpd/files/uhttpd.config +++ b/package/uhttpd/files/uhttpd.config @@ -12,6 +12,11 @@ config uhttpd main # Server document root option home /www + # Reject requests from RFC1918 IP addresses + # directed to the servers public IP(s). + # This is a DNS rebinding countermeasure. + option rfc1918_filter 1 + # Certificate and private key for HTTPS. # If no listen_https addresses are given, # the key options are ignored. diff --git a/package/uhttpd/files/uhttpd.init b/package/uhttpd/files/uhttpd.init index 58f980c42f..b00b2e281b 100755 --- a/package/uhttpd/files/uhttpd.init +++ b/package/uhttpd/files/uhttpd.init @@ -17,6 +17,17 @@ append_arg() { [ -n "$val" -o -n "$def" ] && append UHTTPD_ARGS "$opt ${val:-$def}" } +append_bool() { + local cfg="$1" + local var="$2" + local opt="$3" + local def="$4" + local val + + config_get_bool val "$cfg" "$var" "$def" + [ "$val" = 1 ] && append UHTTPD_ARGS "$opt" +} + generate_keys() { local cfg="$1" local key="$2" @@ -59,6 +70,12 @@ start_instance() append_arg "$cfg" lua_handler "-L" append_arg "$cfg" script_timeout "-t" append_arg "$cfg" network_timeout "-T" + append_arg "$cfg" error_page "-E" + append_arg "$cfg" index_page "-I" + + append_bool "$cfg" no_symlinks "-S" 0 + append_bool "$cfg" no_dirlists "-D" 0 + append_bool "$cfg" rfc1918_filter "-R" 0 config_get http "$cfg" listen_http for listen in $http; do diff --git a/package/uhttpd/src/uhttpd-cgi.c b/package/uhttpd/src/uhttpd-cgi.c index 855a72f569..0861249162 100644 --- a/package/uhttpd/src/uhttpd-cgi.c +++ b/package/uhttpd/src/uhttpd-cgi.c @@ -234,6 +234,17 @@ void uh_cgi_request(struct client *cl, struct http_request *req, struct path_inf if( pi->info ) setenv("PATH_INFO", pi->info, 1); + /* REDIRECT_STATUS, php-cgi wants it */ + switch( req->redirect_status ) + { + case 404: + setenv("REDIRECT_STATUS", "404", 1); + break; + + default: + setenv("REDIRECT_STATUS", "200", 1); + break; + } /* http version */ if( req->version > 1.0 ) diff --git a/package/uhttpd/src/uhttpd-file.c b/package/uhttpd/src/uhttpd-file.c index 81f66a34b0..850a14175c 100644 --- a/package/uhttpd/src/uhttpd-file.c +++ b/package/uhttpd/src/uhttpd-file.c @@ -29,7 +29,7 @@ static const char * uh_file_mime_lookup(const char *path) { struct mimetype *m = &uh_mime_types[0]; - char *e; + const char *e; while( m->extn ) { @@ -275,7 +275,9 @@ static void uh_file_dirlist(struct client *cl, struct http_request *req, struct strncat(filename, files[i]->d_name, sizeof(filename) - strlen(files[i]->d_name)); - if( !stat(filename, &s) && (s.st_mode & S_IFDIR) ) + if( !stat(filename, &s) && + (s.st_mode & S_IFDIR) && (s.st_mode & S_IXOTH) + ) uh_http_sendf(cl, req, "
  • %s/
    " "modified: %s
    directory - %.02f kbyte" @@ -293,7 +295,9 @@ static void uh_file_dirlist(struct client *cl, struct http_request *req, struct strncat(filename, files[i]->d_name, sizeof(filename) - strlen(files[i]->d_name)); - if( !stat(filename, &s) && !(s.st_mode & S_IFDIR) ) + if( !stat(filename, &s) && + !(s.st_mode & S_IFDIR) && (s.st_mode & S_IROTH) + ) uh_http_sendf(cl, req, "
  • %s
    " "modified: %s
    %s - %.02f kbyte
    " @@ -369,7 +373,7 @@ void uh_file_request(struct client *cl, struct http_request *req, struct path_in } /* directory */ - else if( pi->stat.st_mode & S_IFDIR ) + else if( (pi->stat.st_mode & S_IFDIR) && !cl->server->conf->no_dirlists ) { /* write status */ uh_file_response_200(cl, req, NULL); diff --git a/package/uhttpd/src/uhttpd-utils.c b/package/uhttpd/src/uhttpd-utils.c index caa6b12bc6..4a1423c715 100644 --- a/package/uhttpd/src/uhttpd-utils.c +++ b/package/uhttpd/src/uhttpd-utils.c @@ -59,6 +59,21 @@ int sa_port(void *sa) return ntohs(((struct sockaddr_in6 *)sa)->sin6_port); } +int sa_rfc1918(void *sa) +{ + struct sockaddr_in *v4 = (struct sockaddr_in *)sa; + unsigned long a = htonl(v4->sin_addr.s_addr); + + if( v4->sin_family == AF_INET ) + { + return ((a >= 0x0A000000) && (a <= 0x0AFFFFFF)) || + ((a >= 0xAC100000) && (a <= 0xAC1FFFFF)) || + ((a >= 0xC0A80000) && (a <= 0xC0A8FFFF)); + } + + return 0; +} + /* Simple strstr() like function that takes len arguments for both haystack and needle. */ char *strfind(char *haystack, int hslen, const char *needle, int ndlen) { @@ -464,6 +479,9 @@ struct path_info * uh_path_lookup(struct client *cl, const char *url) int i = 0; struct stat s; + /* back out early if url is undefined */ + if ( url == NULL ) + return NULL; memset(path_phys, 0, sizeof(path_phys)); memset(path_info, 0, sizeof(path_info)); @@ -550,18 +568,31 @@ struct path_info * uh_path_lookup(struct client *cl, const char *url) memcpy(buffer, path_phys, sizeof(buffer)); pathptr = &buffer[strlen(buffer)]; - for( i = 0; i < array_size(uh_index_files); i++ ) + if( cl->server->conf->index_file ) { - strncat(buffer, uh_index_files[i], sizeof(buffer)); + strncat(buffer, cl->server->conf->index_file, sizeof(buffer)); if( !stat(buffer, &s) && (s.st_mode & S_IFREG) ) { memcpy(path_phys, buffer, sizeof(path_phys)); memcpy(&p.stat, &s, sizeof(p.stat)); - break; } + } + else + { + for( i = 0; i < array_size(uh_index_files); i++ ) + { + strncat(buffer, uh_index_files[i], sizeof(buffer)); - *pathptr = 0; + if( !stat(buffer, &s) && (s.st_mode & S_IFREG) ) + { + memcpy(path_phys, buffer, sizeof(path_phys)); + memcpy(&p.stat, &s, sizeof(p.stat)); + break; + } + + *pathptr = 0; + } } p.root = docroot; diff --git a/package/uhttpd/src/uhttpd-utils.h b/package/uhttpd/src/uhttpd-utils.h index a6448b63bc..1b18265417 100644 --- a/package/uhttpd/src/uhttpd-utils.h +++ b/package/uhttpd/src/uhttpd-utils.h @@ -49,6 +49,7 @@ struct path_info { const char * sa_straddr(void *sa); const char * sa_strport(void *sa); int sa_port(void *sa); +int sa_rfc1918(void *sa); char *strfind(char *haystack, int hslen, const char *needle, int ndlen); diff --git a/package/uhttpd/src/uhttpd.c b/package/uhttpd/src/uhttpd.c index 2f77a32a96..be882470ad 100644 --- a/package/uhttpd/src/uhttpd.c +++ b/package/uhttpd/src/uhttpd.c @@ -47,7 +47,7 @@ static void uh_sigchld(int sig) while( waitpid(-1, NULL, WNOHANG) > 0 ) { } } -static void uh_config_parse(const char *path) +static void uh_config_parse(struct config *conf) { FILE *c; char line[512]; @@ -55,7 +55,10 @@ static void uh_config_parse(const char *path) char *pass = NULL; char *eol = NULL; - if( (c = fopen(path ? path : "/etc/httpd.conf", "r")) != NULL ) + const char *path = conf->file ? conf->file : "/etc/httpd.conf"; + + + if( (c = fopen(path, "r")) != NULL ) { memset(line, 0, sizeof(line)); @@ -74,9 +77,23 @@ static void uh_config_parse(const char *path) "Notice: No password set for user %s, ignoring " "authentication on %s\n", user, line ); + } + } + else if( !strncmp(line, "I:", 2) ) + { + if( !(user = strchr(line, ':')) || (*user++ = 0) || + !(eol = strchr(user, '\n')) || (*eol++ = 0) ) + continue; - break; - } + conf->index_file = strdup(user); + } + else if( !strncmp(line, "E404:", 5) ) + { + if( !(user = strchr(line, ':')) || (*user++ = 0) || + !(eol = strchr(user, '\n')) || (*eol++ = 0) ) + continue; + + conf->error_handler = strdup(user); } } @@ -302,6 +319,7 @@ static struct http_request * uh_http_header_parse(struct client *cl, char *buffe } /* valid enough */ + req.redirect_status = 200; return &req; } @@ -505,8 +523,9 @@ int main (int argc, char **argv) } #endif - while( (opt = getopt(argc, argv, "fSC:K:p:s:h:c:l:L:d:r:m:x:t:T:")) > 0 ) - { + while( (opt = getopt(argc, argv, + "fSDRC:K:E:I:p:s:h:c:l:L:d:r:m:x:t:T:")) > 0 + ) { switch(opt) { /* [addr:]port */ @@ -597,11 +616,42 @@ int main (int argc, char **argv) } break; + /* error handler */ + case 'E': + if( (strlen(optarg) == 0) || (optarg[0] != '/') ) + { + fprintf(stderr, "Error: Invalid error handler: %s\n", + optarg); + exit(1); + } + conf.error_handler = optarg; + break; + + /* index file */ + case 'I': + if( (strlen(optarg) == 0) || (optarg[0] == '/') ) + { + fprintf(stderr, "Error: Invalid index page: %s\n", + optarg); + exit(1); + } + conf.index_file = optarg; + break; + /* don't follow symlinks */ case 'S': conf.no_symlinks = 1; break; + /* don't list directories */ + case 'D': + conf.no_dirlists = 1; + break; + + case 'R': + conf.rfc1918_filter = 1; + break; + #ifdef HAVE_CGI /* cgi prefix */ case 'x': @@ -678,7 +728,11 @@ int main (int argc, char **argv) " -K file ASN.1 server private key file\n" #endif " -h directory Specify the document root, default is '.'\n" + " -E string Use given virtual URL as 404 error handler\n" + " -I string Use given filename as index page for directories\n" " -S Do not follow symbolic links outside of the docroot\n" + " -D Do not allow directory listings, send 403 instead\n" + " -R Enable RFC1918 filter\n" #ifdef HAVE_LUA " -l string URL prefix for Lua handler, default is '/lua'\n" " -L file Lua handler script, omit to disable Lua\n" @@ -727,7 +781,7 @@ int main (int argc, char **argv) conf.realm = "Protected Area"; /* config file */ - uh_config_parse(conf.file); + uh_config_parse(&conf); /* default network timeout */ if( conf.network_timeout <= 0 ) @@ -883,6 +937,14 @@ int main (int argc, char **argv) /* parse message header */ if( (req = uh_http_header_recv(cl)) != NULL ) { + /* RFC1918 filtering required? */ + if( conf.rfc1918_filter && sa_rfc1918(&cl->peeraddr) && + !sa_rfc1918(&cl->servaddr) ) + { + uh_http_sendhf(cl, 403, "Forbidden", + "Rejected request from RFC1918 IP to public server address"); + } + else #ifdef HAVE_LUA /* Lua request? */ if( L && uh_path_match(conf.lua_prefix, req->url) ) @@ -913,8 +975,29 @@ int main (int argc, char **argv) /* 404 */ else { - uh_http_sendhf(cl, 404, "Not Found", - "No such file or directory"); + /* Try to invoke an error handler */ + pin = uh_path_lookup(cl, conf.error_handler); + + if( pin && uh_auth_check(cl, req, pin) ) + { + req->redirect_status = 404; + +#ifdef HAVE_CGI + if( uh_path_match(conf.cgi_prefix, pin->name) ) + { + uh_cgi_request(cl, req, pin); + } + else +#endif + { + uh_file_request(cl, req, pin); + } + } + else + { + uh_http_sendhf(cl, 404, "Not Found", + "No such file or directory"); + } } } diff --git a/package/uhttpd/src/uhttpd.h b/package/uhttpd/src/uhttpd.h index 32e3970072..fd2176ebdd 100644 --- a/package/uhttpd/src/uhttpd.h +++ b/package/uhttpd/src/uhttpd.h @@ -64,8 +64,12 @@ struct config { char docroot[PATH_MAX]; char *realm; char *file; + char *index_file; + char *error_handler; int no_symlinks; + int no_dirlists; int network_timeout; + int rfc1918_filter; #ifdef HAVE_CGI char *cgi_prefix; #endif @@ -124,6 +128,7 @@ struct auth_realm { struct http_request { int method; float version; + int redirect_status; char *url; char *headers[UH_LIMIT_HEADERS]; struct auth_realm *realm;