static struct mimetype uh_mime_types[] = {
- { "txt", "text/plain" },
- { "log", "text/plain" },
- { "js", "text/javascript" },
- { "css", "text/css" },
- { "htm", "text/html" },
- { "html", "text/html" },
- { "diff", "text/x-patch" },
- { "patch", "text/x-patch" },
- { "c", "text/x-csrc" },
- { "h", "text/x-chdr" },
- { "o", "text/x-object" },
- { "ko", "text/x-object" },
+ { "txt", "text/plain" },
+ { "log", "text/plain" },
+ { "js", "text/javascript" },
+ { "css", "text/css" },
+ { "htm", "text/html" },
+ { "html", "text/html" },
+ { "diff", "text/x-patch" },
+ { "patch", "text/x-patch" },
+ { "c", "text/x-csrc" },
+ { "h", "text/x-chdr" },
+ { "o", "text/x-object" },
+ { "ko", "text/x-object" },
- { "bmp", "image/bmp" },
- { "gif", "image/gif" },
- { "png", "image/png" },
- { "jpg", "image/jpeg" },
- { "jpeg", "image/jpeg" },
- { "svg", "image/svg+xml" },
+ { "bmp", "image/bmp" },
+ { "gif", "image/gif" },
+ { "png", "image/png" },
+ { "jpg", "image/jpeg" },
+ { "jpeg", "image/jpeg" },
+ { "svg", "image/svg+xml" },
- { "zip", "application/zip" },
- { "pdf", "application/pdf" },
- { "xml", "application/xml" },
- { "xsl", "application/xml" },
- { "doc", "application/msword" },
- { "ppt", "application/vnd.ms-powerpoint" },
- { "xls", "application/vnd.ms-excel" },
- { "odt", "application/vnd.oasis.opendocument.text" },
- { "odp", "application/vnd.oasis.opendocument.presentation" },
- { "pl", "application/x-perl" },
- { "sh", "application/x-shellscript" },
- { "php", "application/x-php" },
- { "deb", "application/x-deb" },
- { "iso", "application/x-cd-image" },
- { "tgz", "application/x-compressed-tar" },
- { "gz", "application/x-gzip" },
- { "bz2", "application/x-bzip" },
- { "tar", "application/x-tar" },
- { "rar", "application/x-rar-compressed" },
+ { "zip", "application/zip" },
+ { "pdf", "application/pdf" },
+ { "xml", "application/xml" },
+ { "xsl", "application/xml" },
+ { "doc", "application/msword" },
+ { "ppt", "application/vnd.ms-powerpoint" },
+ { "xls", "application/vnd.ms-excel" },
+ { "odt", "application/vnd.oasis.opendocument.text" },
+ { "odp", "application/vnd.oasis.opendocument.presentation" },
+ { "pl", "application/x-perl" },
+ { "sh", "application/x-shellscript" },
+ { "php", "application/x-php" },
+ { "deb", "application/x-deb" },
+ { "iso", "application/x-cd-image" },
+ { "tar.gz", "application/x-compressed-tar" },
+ { "tgz", "application/x-compressed-tar" },
+ { "gz", "application/x-gzip" },
+ { "tar.bz2", "application/x-bzip-compressed-tar" },
+ { "tbz", "application/x-bzip-compressed-tar" },
+ { "bz2", "application/x-bzip" },
+ { "tar", "application/x-tar" },
+ { "rar", "application/x-rar-compressed" },
- { "mp3", "audio/mpeg" },
- { "ogg", "audio/x-vorbis+ogg" },
- { "wav", "audio/x-wav" },
+ { "mp3", "audio/mpeg" },
+ { "ogg", "audio/x-vorbis+ogg" },
+ { "wav", "audio/x-wav" },
- { "mpg", "video/mpeg" },
- { "mpeg", "video/mpeg" },
- { "avi", "video/x-msvideo" },
+ { "mpg", "video/mpeg" },
+ { "mpeg", "video/mpeg" },
+ { "avi", "video/x-msvideo" },
- { "README", "text/plain" },
- { "log", "text/plain" },
- { "cfg", "text/plain" },
- { "conf", "text/plain" },
+ { "README", "text/plain" },
+ { "log", "text/plain" },
+ { "cfg", "text/plain" },
+ { "conf", "text/plain" },
{ NULL, NULL }
};
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 )
{
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)
{
char *docroot = cl->server->conf->docroot;
char *pathptr = NULL;
+ int no_sym = cl->server->conf->no_symlinks;
int i = 0;
struct stat s;
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));
/* maximum file descriptor number */
int new_fd, cur_fd, max_fd = 0;
+#ifdef HAVE_TLS
int tls = 0;
int keys = 0;
+#endif
+
int bound = 0;
int nofork = 0;
char bind[128];
char *port = NULL;
- /* library handles */
- void *tls_lib;
- void *lua_lib;
+#if defined(HAVE_TLS) || defined(HAVE_LUA)
+ /* library handle */
+ void *lib;
+#endif
/* clear the master and temp sets */
FD_ZERO(&used_fds);
#ifdef HAVE_TLS
/* load TLS plugin */
- if( ! (tls_lib = dlopen("uhttpd_tls.so", RTLD_LAZY | RTLD_GLOBAL)) )
+ if( ! (lib = dlopen("uhttpd_tls.so", RTLD_LAZY | RTLD_GLOBAL)) )
{
fprintf(stderr,
"Notice: Unable to load TLS plugin - disabling SSL support! "
else
{
/* resolve functions */
- if( !(conf.tls_init = dlsym(tls_lib, "uh_tls_ctx_init")) ||
- !(conf.tls_cert = dlsym(tls_lib, "uh_tls_ctx_cert")) ||
- !(conf.tls_key = dlsym(tls_lib, "uh_tls_ctx_key")) ||
- !(conf.tls_free = dlsym(tls_lib, "uh_tls_ctx_free")) ||
- !(conf.tls_accept = dlsym(tls_lib, "uh_tls_client_accept")) ||
- !(conf.tls_close = dlsym(tls_lib, "uh_tls_client_close")) ||
- !(conf.tls_recv = dlsym(tls_lib, "uh_tls_client_recv")) ||
- !(conf.tls_send = dlsym(tls_lib, "uh_tls_client_send"))
+ if( !(conf.tls_init = dlsym(lib, "uh_tls_ctx_init")) ||
+ !(conf.tls_cert = dlsym(lib, "uh_tls_ctx_cert")) ||
+ !(conf.tls_key = dlsym(lib, "uh_tls_ctx_key")) ||
+ !(conf.tls_free = dlsym(lib, "uh_tls_ctx_free")) ||
+ !(conf.tls_accept = dlsym(lib, "uh_tls_client_accept")) ||
+ !(conf.tls_close = dlsym(lib, "uh_tls_client_close")) ||
+ !(conf.tls_recv = dlsym(lib, "uh_tls_client_recv")) ||
+ !(conf.tls_send = dlsym(lib, "uh_tls_client_send"))
) {
fprintf(stderr,
"Error: Failed to lookup required symbols "
}
#endif
- while( (opt = getopt(argc, argv, "fC:K:p:s:h:c:l:L:d:r:m:x:t:")) > 0 )
+ while( (opt = getopt(argc, argv, "fSC:K:p:s:h:c:l:L:d:r:m:x:t:T:")) > 0 )
{
switch(opt)
{
}
break;
+ /* don't follow symlinks */
+ case 'S':
+ conf.no_symlinks = 1;
+ break;
+
#ifdef HAVE_CGI
/* cgi prefix */
case 'x':
break;
#endif
+ /* network timeout */
+ case 'T':
+ conf.network_timeout = atoi(optarg);
+ break;
+
/* no fork */
case 'f':
nofork = 1;
" -K file ASN.1 server private key file\n"
#endif
" -h directory Specify the document root, default is '.'\n"
+ " -S Do not follow symbolic links outside of the docroot\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"
#if defined(HAVE_CGI) || defined(HAVE_LUA)
" -t seconds CGI and Lua script timeout in seconds, default is 60\n"
#endif
+ " -T seconds Network timeout in seconds, default is 30\n"
" -d string URL decode given string\n"
" -r string Specify basic auth realm\n"
" -m string MD5 crypt given string\n"
/* config file */
uh_config_parse(conf.file);
+ /* default network timeout */
+ if( conf.network_timeout <= 0 )
+ conf.network_timeout = 30;
+
#if defined(HAVE_CGI) || defined(HAVE_LUA)
/* default script timeout */
if( conf.script_timeout <= 0 )
#ifdef HAVE_LUA
/* load Lua plugin */
- if( ! (lua_lib = dlopen("uhttpd_lua.so", RTLD_LAZY | RTLD_GLOBAL)) )
+ if( ! (lib = dlopen("uhttpd_lua.so", RTLD_LAZY | RTLD_GLOBAL)) )
{
fprintf(stderr,
"Notice: Unable to load Lua plugin - disabling Lua support! "
else
{
/* resolve functions */
- if( !(conf.lua_init = dlsym(lua_lib, "uh_lua_init")) ||
- !(conf.lua_close = dlsym(lua_lib, "uh_lua_close")) ||
- !(conf.lua_request = dlsym(lua_lib, "uh_lua_request"))
+ if( !(conf.lua_init = dlsym(lib, "uh_lua_init")) ||
+ !(conf.lua_close = dlsym(lib, "uh_lua_close")) ||
+ !(conf.lua_request = dlsym(lib, "uh_lua_request"))
) {
fprintf(stderr,
"Error: Failed to lookup required symbols "