Continued THTTPD debug
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@2023 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
parent
8ec0fc92ed
commit
275133b216
@ -89,11 +89,13 @@ static inline int statpsuedo(FAR struct inode *inode, FAR struct stat *buf)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If it has no operations, then it must just be a intermeidate
|
||||
/* If it has no operations, then it must just be a intermediate
|
||||
* node in the inode tree. It is something like a directory.
|
||||
* We'll say that all psuedo-directories are read-able but not
|
||||
* write-able.
|
||||
*/
|
||||
|
||||
buf->st_mode |= S_IFDIR;
|
||||
buf->st_mode |= S_IFDIR|S_IROTH|S_IRGRP|S_IRUSR;
|
||||
}
|
||||
|
||||
return OK;
|
||||
@ -108,7 +110,7 @@ static inline int statroot(FAR struct stat *buf)
|
||||
/* There is no inode associated with the fake root directory */
|
||||
|
||||
memset(buf, 0, sizeof(struct stat) );
|
||||
buf->st_mode = S_IFDIR;
|
||||
buf->st_mode = S_IFDIR|S_IROTH|S_IRGRP|S_IRUSR;
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
@ -197,7 +197,6 @@ static int cgi_child(int argc, char **argv);
|
||||
static int cgi(httpd_conn *hc);
|
||||
#endif
|
||||
|
||||
static int really_start_request(httpd_conn *hc, struct timeval *nowP);
|
||||
static int check_referer(httpd_conn *hc);
|
||||
#ifdef CONFIG_THTTPD_URLPATTERN
|
||||
static int really_check_referer(httpd_conn *hc);
|
||||
@ -226,6 +225,10 @@ static pid_t main_thread;
|
||||
static int str_alloc_count = 0;
|
||||
static size_t str_alloc_size = 0;
|
||||
|
||||
/* This is the 'root' of the Filesystem as seen by the HTTP client */
|
||||
|
||||
static const char httpd_root[] = CONFIG_THTTPD_PATH;
|
||||
|
||||
/* Include MIME encodings and types */
|
||||
|
||||
#include "mime_types.h"
|
||||
@ -738,7 +741,7 @@ static int auth_check(httpd_conn *hc, char *dirname)
|
||||
else
|
||||
#endif
|
||||
{
|
||||
topdir = CONFIG_THTTPD_PATH;
|
||||
topdir = httpd_root;
|
||||
}
|
||||
|
||||
switch (auth_check2(hc, topdir))
|
||||
@ -1248,12 +1251,16 @@ static char *expand_filename(char *path, char **restP, boolean tildemapped)
|
||||
static char *rest;
|
||||
static size_t maxchecked = 0, maxrest = 0;
|
||||
size_t checkedlen, restlen, prevcheckedlen, prevrestlen;
|
||||
#if 0 // REVISIT
|
||||
struct stat sb;
|
||||
#endif
|
||||
int nlinks, i;
|
||||
char *r;
|
||||
char *cp1;
|
||||
char *cp2;
|
||||
|
||||
nvdbg("path: \"%s\"\n", path);
|
||||
#if 0 // REVISIT
|
||||
/* We need to do the pathinfo check. we do a single stat() of the whole
|
||||
* filename - if it exists, then we return it as is with nothing in restP.
|
||||
* If it doesn't exist, we fall through to the existing code.
|
||||
@ -1278,12 +1285,36 @@ static char *expand_filename(char *path, char **restP, boolean tildemapped)
|
||||
*restP = rest;
|
||||
return checked;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Start out with nothing in checked and the whole filename in rest. */
|
||||
/* Handle leading /, or . or by copying the default directory into checked */
|
||||
|
||||
if (path[0] == '.' || (path[0] == '/' && strncmp(path, httpd_root, strlen(httpd_root)) != 0))
|
||||
{
|
||||
/* Start out with httpd_root in checked */
|
||||
|
||||
checkedlen = strlen(httpd_root) + 1;
|
||||
httpd_realloc_str(&checked, &maxchecked, checkedlen);
|
||||
strcpy(checked, httpd_root);
|
||||
|
||||
/* Skip over leading '.' */
|
||||
|
||||
if (path[0] == '.')
|
||||
{
|
||||
path++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Start out with nothing in checked */
|
||||
|
||||
httpd_realloc_str(&checked, &maxchecked, 1);
|
||||
checked[0] = '\0';
|
||||
checkedlen = 0;
|
||||
}
|
||||
|
||||
/* Copy the whole filename (minus the leading '.') into rest. */
|
||||
|
||||
httpd_realloc_str(&checked, &maxchecked, 1);
|
||||
checked[0] = '\0';
|
||||
checkedlen = 0;
|
||||
restlen = strlen(path);
|
||||
httpd_realloc_str(&rest, &maxrest, restlen);
|
||||
(void)strcpy(rest, path);
|
||||
@ -1295,17 +1326,6 @@ static char *expand_filename(char *path, char **restP, boolean tildemapped)
|
||||
rest[--restlen] = '\0';
|
||||
}
|
||||
|
||||
if (!tildemapped)
|
||||
{
|
||||
/* Remove any leading slashes. */
|
||||
|
||||
while (rest[0] == '/')
|
||||
{
|
||||
(void)strcpy(rest, &(rest[1]));
|
||||
--restlen;
|
||||
}
|
||||
}
|
||||
|
||||
r = rest;
|
||||
nlinks = 0;
|
||||
|
||||
@ -1316,7 +1336,7 @@ static char *expand_filename(char *path, char **restP, boolean tildemapped)
|
||||
/* Save current checkedlen. Save current restlen in case we get a non-existant component. */
|
||||
|
||||
prevcheckedlen = checkedlen;
|
||||
prevrestlen = restlen;
|
||||
prevrestlen = restlen;
|
||||
|
||||
/* Grab one component from r and transfer it to checked. */
|
||||
|
||||
@ -1418,8 +1438,10 @@ static char *expand_filename(char *path, char **restP, boolean tildemapped)
|
||||
*restP = r;
|
||||
if (checked[0] == '\0')
|
||||
{
|
||||
(void)strcpy(checked, CONFIG_THTTPD_PATH);
|
||||
(void)strcpy(checked, httpd_root);
|
||||
}
|
||||
|
||||
nvdbg("checked: \"%s\"\n", checked);
|
||||
return checked;
|
||||
}
|
||||
|
||||
@ -2108,11 +2130,11 @@ static void create_environment(httpd_conn *hc)
|
||||
(void)snprintf(buf, sizeof(buf), "/%s", hc->pathinfo);
|
||||
setenv("PATH_INFO", buf, TRUE);
|
||||
|
||||
l = strlen(CONFIG_THTTPD_PATH) + strlen(hc->pathinfo) + 1;
|
||||
l = strlen(httpd_root) + strlen(hc->pathinfo) + 1;
|
||||
cp2 = NEW(char, l);
|
||||
if (cp2)
|
||||
{
|
||||
(void)snprintf(cp2, l, "%s%s", CONFIG_THTTPD_PATH, hc->pathinfo);
|
||||
(void)snprintf(cp2, l, "%s%s", httpd_root, hc->pathinfo);
|
||||
setenv("PATH_TRANSLATED", cp2, TRUE);
|
||||
}
|
||||
}
|
||||
@ -2890,307 +2912,6 @@ static int cgi(httpd_conn *hc)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int really_start_request(httpd_conn *hc, struct timeval *nowP)
|
||||
{
|
||||
static char *indexname;
|
||||
static size_t maxindexname = 0;
|
||||
static const char *index_names[] = { CONFIG_THTTPD_INDEX_NAMES };
|
||||
int i;
|
||||
#ifdef CONFIG_THTTPD_AUTH_FILE
|
||||
static char *dirname;
|
||||
static size_t maxdirname = 0;
|
||||
#endif /* CONFIG_THTTPD_AUTH_FILE */
|
||||
size_t expnlen, indxlen;
|
||||
char *cp;
|
||||
char *pi;
|
||||
|
||||
expnlen = strlen(hc->expnfilename);
|
||||
|
||||
if (hc->method != METHOD_GET && hc->method != METHOD_HEAD &&
|
||||
hc->method != METHOD_POST)
|
||||
{
|
||||
NOTIMPLEMENTED("really start");
|
||||
httpd_send_err(hc, 501, err501title, "", err501form,
|
||||
httpd_method_str(hc->method));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Stat the file. */
|
||||
if (stat(hc->expnfilename, &hc->sb) < 0)
|
||||
{
|
||||
INTERNALERROR(hc->expnfilename);
|
||||
httpd_send_err(hc, 500, err500title, "", err500form, hc->encodedurl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Is it world-readable or world-executable? We check explicitly instead
|
||||
* of just trying to open it, so that no one ever gets surprised by a file
|
||||
* that's not set world-readable and yet somehow is readable by the HTTP
|
||||
* server and therefore the *whole* world.
|
||||
*/
|
||||
|
||||
if (!(hc->sb.st_mode & (S_IROTH | S_IXOTH)))
|
||||
{
|
||||
ndbg("%s URL \"%s\" resolves to a non world-readable file\n",
|
||||
httpd_ntoa(&hc->client_addr), hc->encodedurl);
|
||||
httpd_send_err(hc, 403, err403title, "",
|
||||
ERROR_FORM(err403form,
|
||||
"The requested URL '%s' resolves to a file that is not world-readable.\n"),
|
||||
hc->encodedurl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Is it a directory? */
|
||||
|
||||
if (S_ISDIR(hc->sb.st_mode))
|
||||
{
|
||||
/* If there's pathinfo, it's just a non-existent file. */
|
||||
|
||||
if (hc->pathinfo[0] != '\0')
|
||||
{
|
||||
httpd_send_err(hc, 404, err404title, "", err404form, hc->encodedurl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Special handling for directory URLs that don't end in a slash. We
|
||||
* send back an explicit redirect with the slash, because otherwise
|
||||
* many clients can't build relative URLs properly.
|
||||
*/
|
||||
|
||||
if (strcmp(hc->origfilename, "") != 0 &&
|
||||
strcmp(hc->origfilename, ".") != 0 &&
|
||||
hc->origfilename[strlen(hc->origfilename) - 1] != '/')
|
||||
{
|
||||
send_dirredirect(hc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check for an index file. */
|
||||
|
||||
for (i = 0; i < sizeof(index_names) / sizeof(char *); ++i)
|
||||
{
|
||||
httpd_realloc_str(&indexname, &maxindexname,
|
||||
expnlen + 1 + strlen(index_names[i]));
|
||||
(void)strcpy(indexname, hc->expnfilename);
|
||||
indxlen = strlen(indexname);
|
||||
if (indxlen == 0 || indexname[indxlen - 1] != '/')
|
||||
{
|
||||
(void)strcat(indexname, "/");
|
||||
}
|
||||
|
||||
if (strcmp(indexname, "./") == 0)
|
||||
{
|
||||
indexname[0] = '\0';
|
||||
}
|
||||
|
||||
(void)strcat(indexname, index_names[i]);
|
||||
if (stat(indexname, &hc->sb) >= 0)
|
||||
{
|
||||
goto got_one;
|
||||
}
|
||||
}
|
||||
|
||||
/* Nope, no index file, so it's an actual directory request. */
|
||||
#ifdef CONFIG_THTTPD_GENERATE_INDICES
|
||||
/* Directories must be readable for indexing. */
|
||||
if (!(hc->sb.st_mode & S_IROTH))
|
||||
{
|
||||
ndbg("%s URL \"%s\" tried to index a directory with indexing disabled\n",
|
||||
httpd_ntoa(&hc->client_addr), hc->encodedurl);
|
||||
httpd_send_err(hc, 403, err403title, "",
|
||||
ERROR_FORM(err403form,
|
||||
"The requested URL '%s' resolves to a directory that has indexing disabled.\n"),
|
||||
hc->encodedurl);
|
||||
return -1;
|
||||
}
|
||||
# ifdef CONFIG_THTTPD_AUTH_FILE
|
||||
/* Check authorization for this directory. */
|
||||
|
||||
if (auth_check(hc, hc->expnfilename) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
# endif /* CONFIG_THTTPD_AUTH_FILE */
|
||||
|
||||
/* Referer check. */
|
||||
|
||||
if (!check_referer(hc))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Ok, generate an index. */
|
||||
return ls(hc);
|
||||
#else
|
||||
ndbg("%s URL \"%s\" tried to index a directory\n",
|
||||
httpd_ntoa(&hc->client_addr), hc->encodedurl);
|
||||
httpd_send_err(hc, 403, err403title, "",
|
||||
ERROR_FORM(err403form,
|
||||
"The requested URL '%s' is a directory, and directory indexing is disabled on this server.\n"),
|
||||
hc->encodedurl);
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
got_one:
|
||||
|
||||
/* Got an index file. Expand again. More pathinfo means
|
||||
* something went wrong.
|
||||
*/
|
||||
|
||||
cp = expand_filename(indexname, &pi, hc->tildemapped);
|
||||
if (cp == (char *)0 || pi[0] != '\0')
|
||||
{
|
||||
INTERNALERROR(indexname);
|
||||
httpd_send_err(hc, 500, err500title, "", err500form, hc->encodedurl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
expnlen = strlen(cp);
|
||||
httpd_realloc_str(&hc->expnfilename, &hc->maxexpnfilename, expnlen);
|
||||
(void)strcpy(hc->expnfilename, cp);
|
||||
|
||||
/* Now, is the index version world-readable or world-executable? */
|
||||
|
||||
if (!(hc->sb.st_mode & (S_IROTH | S_IXOTH)))
|
||||
{
|
||||
ndbg("%s URL \"%s\" resolves to a non-world-readable index file\n",
|
||||
httpd_ntoa(&hc->client_addr), hc->encodedurl);
|
||||
httpd_send_err(hc, 403, err403title, "",
|
||||
ERROR_FORM(err403form,
|
||||
"The requested URL '%s' resolves to an index file that is not world-readable.\n"),
|
||||
hc->encodedurl);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check authorization for this directory. */
|
||||
|
||||
#ifdef CONFIG_THTTPD_AUTH_FILE
|
||||
httpd_realloc_str(&dirname, &maxdirname, expnlen);
|
||||
(void)strcpy(dirname, hc->expnfilename);
|
||||
cp = strrchr(dirname, '/');
|
||||
if (!cp)
|
||||
{
|
||||
(void)strcpy(dirname, CONFIG_THTTPD_PATH);
|
||||
}
|
||||
else
|
||||
{
|
||||
*cp = '\0';
|
||||
}
|
||||
|
||||
if (auth_check(hc, dirname) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check if the filename is the CONFIG_THTTPD_AUTH_FILE itself - that's verboten. */
|
||||
|
||||
if (expnlen == sizeof(CONFIG_THTTPD_AUTH_FILE) - 1)
|
||||
{
|
||||
if (strcmp(hc->expnfilename, CONFIG_THTTPD_AUTH_FILE) == 0)
|
||||
{
|
||||
ndbg("%s URL \"%s\" tried to retrieve an auth file\n",
|
||||
httpd_ntoa(&hc->client_addr), hc->encodedurl);
|
||||
httpd_send_err(hc, 403, err403title, "",
|
||||
ERROR_FORM(err403form,
|
||||
"The requested URL '%s' is an authorization file, retrieving it is not permitted.\n"),
|
||||
hc->encodedurl);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (expnlen >= sizeof(CONFIG_THTTPD_AUTH_FILE) &&
|
||||
strcmp(&(hc->expnfilename[expnlen - sizeof(CONFIG_THTTPD_AUTH_FILE) + 1]),
|
||||
CONFIG_THTTPD_AUTH_FILE) == 0 &&
|
||||
hc->expnfilename[expnlen - sizeof(CONFIG_THTTPD_AUTH_FILE)] == '/')
|
||||
{
|
||||
ndbg("%s URL \"%s\" tried to retrieve an auth file\n",
|
||||
httpd_ntoa(&hc->client_addr), hc->encodedurl);
|
||||
httpd_send_err(hc, 403, err403title, "",
|
||||
ERROR_FORM(err403form,
|
||||
"The requested URL '%s' is an authorization file, retrieving it is not permitted.\n"),
|
||||
hc->encodedurl);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Referer check. */
|
||||
|
||||
if (!check_referer(hc))
|
||||
return -1;
|
||||
|
||||
/* Is it in the CGI area? */
|
||||
|
||||
#ifdef CONFIG_THTTPD_CGI_PATTERN
|
||||
if (match(CONFIG_THTTPD_CGI_PATTERN, hc->expnfilename))
|
||||
{
|
||||
return cgi(hc);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* It's not CGI. If it's executable or there's pathinfo, someone's trying
|
||||
* to either serve or run a non-CGI file as CGI. Either case is
|
||||
* prohibited.
|
||||
*/
|
||||
|
||||
if (hc->sb.st_mode & S_IXOTH)
|
||||
{
|
||||
ndbg("%s URL \"%s\" is executable but isn't CGI\n",
|
||||
httpd_ntoa(&hc->client_addr), hc->encodedurl);
|
||||
httpd_send_err(hc, 403, err403title, "",
|
||||
ERROR_FORM(err403form,
|
||||
"The requested URL '%s' resolves to a file which is marked executable but is not a CGI file; retrieving it is forbidden.\n"),
|
||||
hc->encodedurl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hc->pathinfo[0] != '\0')
|
||||
{
|
||||
ndbg("%s URL \"%s\" has pathinfo but isn't CGI\n",
|
||||
httpd_ntoa(&hc->client_addr), hc->encodedurl);
|
||||
httpd_send_err(hc, 403, err403title, "",
|
||||
ERROR_FORM(err403form,
|
||||
"The requested URL '%s' resolves to a file plus CGI-style pathinfo, but the file is not a valid CGI file.\n"),
|
||||
hc->encodedurl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Fill in range_end, if necessary. */
|
||||
|
||||
if (hc->got_range &&
|
||||
(hc->range_end == -1 || hc->range_end >= hc->sb.st_size))
|
||||
{
|
||||
hc->range_end = hc->sb.st_size - 1;
|
||||
}
|
||||
|
||||
figure_mime(hc);
|
||||
|
||||
if (hc->method == METHOD_HEAD)
|
||||
{
|
||||
send_mime(hc, 200, ok200title, hc->encodings, "", hc->type,
|
||||
hc->sb.st_size, hc->sb.st_mtime);
|
||||
}
|
||||
else if (hc->if_modified_since != (time_t) - 1 &&
|
||||
hc->if_modified_since >= hc->sb.st_mtime)
|
||||
{
|
||||
send_mime(hc, 304, err304title, hc->encodings, "", hc->type, (off_t) - 1,
|
||||
hc->sb.st_mtime);
|
||||
}
|
||||
else
|
||||
{
|
||||
hc->file_fd = open(hc->expnfilename, O_RDONLY);
|
||||
if (!hc->file_fd < 0)
|
||||
{
|
||||
INTERNALERROR(hc->expnfilename);
|
||||
httpd_send_err(hc, 500, err500title, "", err500form, hc->encodedurl);
|
||||
return -1;
|
||||
}
|
||||
send_mime(hc, 200, ok200title, hc->encodings, "", hc->type,
|
||||
hc->sb.st_size, hc->sb.st_mtime);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns 1 if ok to serve the url, 0 if not. */
|
||||
|
||||
static int check_referer(httpd_conn *hc)
|
||||
@ -4039,7 +3760,7 @@ int httpd_parse_request(httpd_conn *hc)
|
||||
|
||||
if (hc->origfilename[0] == '\0')
|
||||
{
|
||||
(void)strcpy(hc->origfilename, CONFIG_THTTPD_PATH);
|
||||
(void)strcpy(hc->origfilename, ".");
|
||||
}
|
||||
|
||||
/* Extract query string from encoded URL. */
|
||||
@ -4342,9 +4063,7 @@ int httpd_parse_request(httpd_conn *hc)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Expand all symbolic links in the filename. This also gives us any
|
||||
* trailing non-existing components, for pathinfo.
|
||||
*/
|
||||
/* Expand the filename */
|
||||
|
||||
cp = expand_filename(hc->expnfilename, &pi, hc->tildemapped);
|
||||
if (!cp)
|
||||
@ -4358,6 +4077,7 @@ int httpd_parse_request(httpd_conn *hc)
|
||||
(void)strcpy(hc->expnfilename, cp);
|
||||
httpd_realloc_str(&hc->pathinfo, &hc->maxpathinfo, strlen(pi));
|
||||
(void)strcpy(hc->pathinfo, pi);
|
||||
nvdbg("expnfilename: \"%s\" pathinfo: \"%s\"\n", hc->expnfilename, hc->pathinfo);
|
||||
|
||||
/* Remove pathinfo stuff from the original filename too. */
|
||||
|
||||
@ -4377,16 +4097,12 @@ int httpd_parse_request(httpd_conn *hc)
|
||||
|
||||
if (hc->expnfilename[0] == '/')
|
||||
{
|
||||
if (strncmp(hc->expnfilename, CONFIG_THTTPD_PATH, strlen(CONFIG_THTTPD_PATH)) == 0)
|
||||
if (strncmp(hc->expnfilename, httpd_root, strlen(httpd_root)) == 0)
|
||||
{
|
||||
/* Elide the current directory. */
|
||||
|
||||
(void)strcpy(hc->expnfilename, &hc->expnfilename[strlen(CONFIG_THTTPD_PATH)]);
|
||||
}
|
||||
#ifdef CONFIG_THTTPD_TILDE_MAP2
|
||||
else if (hc->altdir[0] != '\0' &&
|
||||
(strncmp(hc->expnfilename, hc->altdir,
|
||||
strlen(hc->altdir)) == 0 &&
|
||||
(strncmp(hc->expnfilename, hc->altdir, strlen(hc->altdir)) == 0 &&
|
||||
(hc->expnfilename[strlen(hc->altdir)] == '\0' ||
|
||||
hc->expnfilename[strlen(hc->altdir)] == '/')))
|
||||
{
|
||||
@ -4448,15 +4164,305 @@ void httpd_destroy_conn(httpd_conn *hc)
|
||||
|
||||
int httpd_start_request(httpd_conn *hc, struct timeval *nowP)
|
||||
{
|
||||
int r;
|
||||
static char *indexname;
|
||||
static size_t maxindexname = 0;
|
||||
static const char *index_names[] = { CONFIG_THTTPD_INDEX_NAMES };
|
||||
int i;
|
||||
#ifdef CONFIG_THTTPD_AUTH_FILE
|
||||
static char *dirname;
|
||||
static size_t maxdirname = 0;
|
||||
#endif /* CONFIG_THTTPD_AUTH_FILE */
|
||||
size_t expnlen, indxlen;
|
||||
char *cp;
|
||||
char *pi;
|
||||
|
||||
/* Really start the request. */
|
||||
nvdbg("File: \"%s\"\n", hc->expnfilename);
|
||||
expnlen = strlen(hc->expnfilename);
|
||||
|
||||
r = really_start_request(hc, nowP);
|
||||
if (hc->method != METHOD_GET && hc->method != METHOD_HEAD &&
|
||||
hc->method != METHOD_POST)
|
||||
{
|
||||
NOTIMPLEMENTED("start");
|
||||
httpd_send_err(hc, 501, err501title, "", err501form,
|
||||
httpd_method_str(hc->method));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* And return the status. */
|
||||
/* Stat the file. */
|
||||
|
||||
return r;
|
||||
if (stat(hc->expnfilename, &hc->sb) < 0)
|
||||
{
|
||||
INTERNALERROR(hc->expnfilename);
|
||||
httpd_send_err(hc, 500, err500title, "", err500form, hc->encodedurl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Is it world-readable or world-executable? We check explicitly instead
|
||||
* of just trying to open it, so that no one ever gets surprised by a file
|
||||
* that's not set world-readable and yet somehow is readable by the HTTP
|
||||
* server and therefore the *whole* world.
|
||||
*/
|
||||
|
||||
if (!(hc->sb.st_mode & (S_IROTH | S_IXOTH)))
|
||||
{
|
||||
ndbg("%s URL \"%s\" resolves to a non world-readable file\n",
|
||||
httpd_ntoa(&hc->client_addr), hc->encodedurl);
|
||||
httpd_send_err(hc, 403, err403title, "",
|
||||
ERROR_FORM(err403form,
|
||||
"The requested URL '%s' resolves to a file that is not world-readable.\n"),
|
||||
hc->encodedurl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Is it a directory? */
|
||||
|
||||
if (S_ISDIR(hc->sb.st_mode))
|
||||
{
|
||||
/* If there's pathinfo, it's just a non-existent file. */
|
||||
|
||||
if (hc->pathinfo[0] != '\0')
|
||||
{
|
||||
httpd_send_err(hc, 404, err404title, "", err404form, hc->encodedurl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Special handling for directory URLs that don't end in a slash. We
|
||||
* send back an explicit redirect with the slash, because otherwise
|
||||
* many clients can't build relative URLs properly.
|
||||
*/
|
||||
|
||||
if (strcmp(hc->origfilename, "") != 0 &&
|
||||
strcmp(hc->origfilename, ".") != 0 &&
|
||||
hc->origfilename[strlen(hc->origfilename) - 1] != '/')
|
||||
{
|
||||
send_dirredirect(hc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check for an index file. */
|
||||
|
||||
for (i = 0; i < sizeof(index_names) / sizeof(char *); ++i)
|
||||
{
|
||||
httpd_realloc_str(&indexname, &maxindexname,
|
||||
expnlen + 1 + strlen(index_names[i]));
|
||||
(void)strcpy(indexname, hc->expnfilename);
|
||||
indxlen = strlen(indexname);
|
||||
if (indxlen == 0 || indexname[indxlen - 1] != '/')
|
||||
{
|
||||
(void)strcat(indexname, "/");
|
||||
}
|
||||
|
||||
if (strcmp(indexname, "./") == 0)
|
||||
{
|
||||
indexname[0] = '\0';
|
||||
}
|
||||
|
||||
(void)strcat(indexname, index_names[i]);
|
||||
if (stat(indexname, &hc->sb) >= 0)
|
||||
{
|
||||
goto got_one;
|
||||
}
|
||||
}
|
||||
|
||||
/* Nope, no index file, so it's an actual directory request. */
|
||||
#ifdef CONFIG_THTTPD_GENERATE_INDICES
|
||||
/* Directories must be readable for indexing. */
|
||||
if (!(hc->sb.st_mode & S_IROTH))
|
||||
{
|
||||
ndbg("%s URL \"%s\" tried to index a directory with indexing disabled\n",
|
||||
httpd_ntoa(&hc->client_addr), hc->encodedurl);
|
||||
httpd_send_err(hc, 403, err403title, "",
|
||||
ERROR_FORM(err403form,
|
||||
"The requested URL '%s' resolves to a directory that has indexing disabled.\n"),
|
||||
hc->encodedurl);
|
||||
return -1;
|
||||
}
|
||||
# ifdef CONFIG_THTTPD_AUTH_FILE
|
||||
/* Check authorization for this directory. */
|
||||
|
||||
if (auth_check(hc, hc->expnfilename) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
# endif /* CONFIG_THTTPD_AUTH_FILE */
|
||||
|
||||
/* Referer check. */
|
||||
|
||||
if (!check_referer(hc))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Ok, generate an index. */
|
||||
return ls(hc);
|
||||
#else
|
||||
ndbg("%s URL \"%s\" tried to index a directory\n",
|
||||
httpd_ntoa(&hc->client_addr), hc->encodedurl);
|
||||
httpd_send_err(hc, 403, err403title, "",
|
||||
ERROR_FORM(err403form,
|
||||
"The requested URL '%s' is a directory, and directory indexing is disabled on this server.\n"),
|
||||
hc->encodedurl);
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
got_one:
|
||||
|
||||
/* Got an index file. Expand again. More pathinfo means
|
||||
* something went wrong.
|
||||
*/
|
||||
|
||||
cp = expand_filename(indexname, &pi, hc->tildemapped);
|
||||
if (cp == (char *)0 || pi[0] != '\0')
|
||||
{
|
||||
INTERNALERROR(indexname);
|
||||
httpd_send_err(hc, 500, err500title, "", err500form, hc->encodedurl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
expnlen = strlen(cp);
|
||||
httpd_realloc_str(&hc->expnfilename, &hc->maxexpnfilename, expnlen);
|
||||
(void)strcpy(hc->expnfilename, cp);
|
||||
|
||||
/* Now, is the index version world-readable or world-executable? */
|
||||
|
||||
if (!(hc->sb.st_mode & (S_IROTH | S_IXOTH)))
|
||||
{
|
||||
ndbg("%s URL \"%s\" resolves to a non-world-readable index file\n",
|
||||
httpd_ntoa(&hc->client_addr), hc->encodedurl);
|
||||
httpd_send_err(hc, 403, err403title, "",
|
||||
ERROR_FORM(err403form,
|
||||
"The requested URL '%s' resolves to an index file that is not world-readable.\n"),
|
||||
hc->encodedurl);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check authorization for this directory. */
|
||||
|
||||
#ifdef CONFIG_THTTPD_AUTH_FILE
|
||||
httpd_realloc_str(&dirname, &maxdirname, expnlen);
|
||||
(void)strcpy(dirname, hc->expnfilename);
|
||||
cp = strrchr(dirname, '/');
|
||||
if (!cp)
|
||||
{
|
||||
(void)strcpy(dirname, httpd_root);
|
||||
}
|
||||
else
|
||||
{
|
||||
*cp = '\0';
|
||||
}
|
||||
|
||||
if (auth_check(hc, dirname) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check if the filename is the CONFIG_THTTPD_AUTH_FILE itself - that's verboten. */
|
||||
|
||||
if (expnlen == sizeof(CONFIG_THTTPD_AUTH_FILE) - 1)
|
||||
{
|
||||
if (strcmp(hc->expnfilename, CONFIG_THTTPD_AUTH_FILE) == 0)
|
||||
{
|
||||
ndbg("%s URL \"%s\" tried to retrieve an auth file\n",
|
||||
httpd_ntoa(&hc->client_addr), hc->encodedurl);
|
||||
httpd_send_err(hc, 403, err403title, "",
|
||||
ERROR_FORM(err403form,
|
||||
"The requested URL '%s' is an authorization file, retrieving it is not permitted.\n"),
|
||||
hc->encodedurl);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (expnlen >= sizeof(CONFIG_THTTPD_AUTH_FILE) &&
|
||||
strcmp(&(hc->expnfilename[expnlen - sizeof(CONFIG_THTTPD_AUTH_FILE) + 1]),
|
||||
CONFIG_THTTPD_AUTH_FILE) == 0 &&
|
||||
hc->expnfilename[expnlen - sizeof(CONFIG_THTTPD_AUTH_FILE)] == '/')
|
||||
{
|
||||
ndbg("%s URL \"%s\" tried to retrieve an auth file\n",
|
||||
httpd_ntoa(&hc->client_addr), hc->encodedurl);
|
||||
httpd_send_err(hc, 403, err403title, "",
|
||||
ERROR_FORM(err403form,
|
||||
"The requested URL '%s' is an authorization file, retrieving it is not permitted.\n"),
|
||||
hc->encodedurl);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Referer check. */
|
||||
|
||||
if (!check_referer(hc))
|
||||
return -1;
|
||||
|
||||
/* Is it in the CGI area? */
|
||||
|
||||
#ifdef CONFIG_THTTPD_CGI_PATTERN
|
||||
if (match(CONFIG_THTTPD_CGI_PATTERN, hc->expnfilename))
|
||||
{
|
||||
return cgi(hc);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* It's not CGI. If it's executable or there's pathinfo, someone's trying
|
||||
* to either serve or run a non-CGI file as CGI. Either case is
|
||||
* prohibited.
|
||||
*/
|
||||
|
||||
if (hc->sb.st_mode & S_IXOTH)
|
||||
{
|
||||
ndbg("%s URL \"%s\" is executable but isn't CGI\n",
|
||||
httpd_ntoa(&hc->client_addr), hc->encodedurl);
|
||||
httpd_send_err(hc, 403, err403title, "",
|
||||
ERROR_FORM(err403form,
|
||||
"The requested URL '%s' resolves to a file which is marked executable but is not a CGI file; retrieving it is forbidden.\n"),
|
||||
hc->encodedurl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hc->pathinfo[0] != '\0')
|
||||
{
|
||||
ndbg("%s URL \"%s\" has pathinfo but isn't CGI\n",
|
||||
httpd_ntoa(&hc->client_addr), hc->encodedurl);
|
||||
httpd_send_err(hc, 403, err403title, "",
|
||||
ERROR_FORM(err403form,
|
||||
"The requested URL '%s' resolves to a file plus CGI-style pathinfo, but the file is not a valid CGI file.\n"),
|
||||
hc->encodedurl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Fill in range_end, if necessary. */
|
||||
|
||||
if (hc->got_range &&
|
||||
(hc->range_end == -1 || hc->range_end >= hc->sb.st_size))
|
||||
{
|
||||
hc->range_end = hc->sb.st_size - 1;
|
||||
}
|
||||
|
||||
figure_mime(hc);
|
||||
|
||||
if (hc->method == METHOD_HEAD)
|
||||
{
|
||||
send_mime(hc, 200, ok200title, hc->encodings, "", hc->type,
|
||||
hc->sb.st_size, hc->sb.st_mtime);
|
||||
}
|
||||
else if (hc->if_modified_since != (time_t) - 1 &&
|
||||
hc->if_modified_since >= hc->sb.st_mtime)
|
||||
{
|
||||
send_mime(hc, 304, err304title, hc->encodings, "", hc->type, (off_t) - 1,
|
||||
hc->sb.st_mtime);
|
||||
}
|
||||
else
|
||||
{
|
||||
hc->file_fd = open(hc->expnfilename, O_RDONLY);
|
||||
if (!hc->file_fd < 0)
|
||||
{
|
||||
INTERNALERROR(hc->expnfilename);
|
||||
httpd_send_err(hc, 500, err500title, "", err500form, hc->encodedurl);
|
||||
return -1;
|
||||
}
|
||||
send_mime(hc, 200, ok200title, hc->encodings, "", hc->type,
|
||||
hc->sb.st_size, hc->sb.st_mtime);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *httpd_ntoa(httpd_sockaddr *saP)
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include "tdate_parse.h"
|
||||
|
||||
@ -170,6 +171,7 @@ static int scan_mon(char *str_mon, long *tm_monP)
|
||||
|
||||
time_t tdate_parse(char *str)
|
||||
{
|
||||
#if 0 // REVISIT -- doesn't work
|
||||
struct tm tm;
|
||||
char *cp;
|
||||
char str_mon[32];
|
||||
@ -184,7 +186,10 @@ time_t tdate_parse(char *str)
|
||||
long tm_wday;
|
||||
#endif
|
||||
|
||||
nvdbg("str: \"%s\"\n", str);
|
||||
|
||||
/* Initialize. */
|
||||
|
||||
(void)memset((char *)&tm, 0, sizeof(struct tm));
|
||||
|
||||
/* Skip initial whitespace ourselves - sscanf is clumsy at this. */
|
||||
@ -315,5 +320,8 @@ time_t tdate_parse(char *str)
|
||||
}
|
||||
|
||||
return mktime(&tm);
|
||||
#else
|
||||
return 0; // for now
|
||||
#endif
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user