diff options
Diffstat (limited to 'package/uhttpd/src/uhttpd-utils.c')
-rw-r--r-- | package/uhttpd/src/uhttpd-utils.c | 82 |
1 files changed, 78 insertions, 4 deletions
diff --git a/package/uhttpd/src/uhttpd-utils.c b/package/uhttpd/src/uhttpd-utils.c index 55b2c410e3..e65f2136d6 100644 --- a/package/uhttpd/src/uhttpd-utils.c +++ b/package/uhttpd/src/uhttpd-utils.c @@ -116,8 +116,8 @@ int uh_tcp_send(struct client *cl, const char *buf, int len) FD_ZERO(&writer); FD_SET(cl->socket, &writer); - timeout.tv_sec = 0; - timeout.tv_usec = 500000; + timeout.tv_sec = cl->server->conf->network_timeout; + timeout.tv_usec = 0; if( select(cl->socket + 1, NULL, &writer, NULL, &timeout) > 0 ) { @@ -376,6 +376,78 @@ int uh_b64decode(char *buf, int blen, const unsigned char *src, int slen) return len; } +static char * canonpath(const char *path, char *path_resolved) +{ + char path_copy[PATH_MAX]; + char *path_cpy = path_copy; + char *path_res = path_resolved; + + struct stat s; + + + /* relative -> absolute */ + if( *path != '/' ) + { + getcwd(path_copy, PATH_MAX); + strncat(path_copy, "/", PATH_MAX - strlen(path_copy)); + strncat(path_copy, path, PATH_MAX - strlen(path_copy)); + } + else + { + strncpy(path_copy, path, PATH_MAX); + } + + /* normalize */ + while( (*path_cpy != '\0') && (path_cpy < (path_copy + PATH_MAX - 2)) ) + { + if( *path_cpy == '/' ) + { + /* skip repeating / */ + if( path_cpy[1] == '/' ) + { + path_cpy++; + continue; + } + + /* /./ or /../ */ + else if( path_cpy[1] == '.' ) + { + /* skip /./ */ + if( (path_cpy[2] == '/') || (path_cpy[2] == '\0') ) + { + path_cpy += 2; + continue; + } + + /* collapse /x/../ */ + else if( path_cpy[2] == '.' ) + { + while( (path_res > path_resolved) && (*--path_res != '/') ) + ; + + path_cpy += 3; + continue; + } + } + } + + *path_res++ = *path_cpy++; + } + + /* remove trailing slash if not root / */ + if( (path_res > (path_resolved+1)) && (path_res[-1] == '/') ) + path_res--; + else if( path_res == path_resolved ) + *path_res++ = '/'; + + *path_res = '\0'; + + /* test access */ + if( !stat(path_resolved, &s) && (s.st_mode & S_IROTH) ) + return path_resolved; + + return NULL; +} struct path_info * uh_path_lookup(struct client *cl, const char *url) { @@ -387,6 +459,7 @@ struct path_info * uh_path_lookup(struct client *cl, const char *url) char *docroot = cl->server->conf->docroot; char *pathptr = NULL; + int no_sym = cl->server->conf->no_symlinks; int i = 0; struct stat s; @@ -432,8 +505,9 @@ struct path_info * uh_path_lookup(struct client *cl, const char *url) memset(path_info, 0, sizeof(path_info)); memcpy(path_info, buffer, min(i + 1, sizeof(path_info) - 1)); - if( realpath(path_info, path_phys) ) - { + if( no_sym ? realpath(path_info, path_phys) + : canonpath(path_info, path_phys) + ) { memset(path_info, 0, sizeof(path_info)); memcpy(path_info, &buffer[i], min(strlen(buffer) - i, sizeof(path_info) - 1)); |