-/* $OpenBSD: httpd.c,v 1.2 2014/07/13 14:17:37 reyk Exp $ */
+/* $OpenBSD: httpd.c,v 1.3 2014/07/23 19:03:56 reyk Exp $ */
/*
* Copyright (c) 2014 Reyk Floeter <reyk@openbsd.org>
return (NULL);
}
+const char *
+canonicalize_path(const char *root, const char *input, char *path, size_t len)
+{
+ const char *i;
+ char *p, *start, *end;
+ size_t n;
+
+ /* assuming input starts with '/' and is nul-terminated */
+ i = input;
+ p = path;
+
+ /* prepend root directory, if specified */
+ if (root != NULL) {
+ if ((n = strlcpy(path, root, len)) >= len)
+ return (NULL);
+ len -= n;
+ p += n;
+ }
+
+ if (*input != '/' || len < 3)
+ return (NULL);
+
+ start = p;
+ end = p + (len - 1);
+
+ /* Set path pointer and make sure that we start with '/' */
+ *p = '\0';
+
+ while (*i != '\0' && p <= end) {
+ /* 1. check for special path elements */
+ if (i[0] == '/') {
+ if (i[1] == '/') {
+ /* a) skip repeating '//' slashes */
+ while (i[1] == '/')
+ i++;
+ continue;
+ } else if (i[1] == '.' && i[2] == '.' &&
+ (i[3] == '/' || i[3] == '\0')) {
+ /* b) revert '..' to previous directory */
+ i += 3;
+ while (p > start && *p != '/')
+ p--;
+ *p = '\0';
+ continue;
+ } else if (i[1] == '.' &&
+ (i[2] == '/' || i[2] == '\0')) {
+ /* c) skip unnecessary '.' current dir */
+ i += 2;
+ continue;
+ }
+ }
+
+ /* 2. copy any other characters */
+ *p++ = *i;
+ i++;
+ }
+ if (p == start)
+ *p++ = '/';
+ *p++ = '\0';
+
+ return (path);
+}
+
void
socket_rlimit(int maxfd)
{
-/* $OpenBSD: httpd.h,v 1.6 2014/07/23 13:26:39 reyk Exp $ */
+/* $OpenBSD: httpd.h,v 1.7 2014/07/23 19:03:56 reyk Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
#define HTTPD_SOCKET "/var/run/httpd.sock"
#define HTTPD_USER "www"
#define HTTPD_SERVERNAME "OpenBSD httpd"
+#define HTTPD_DOCROOT "/htdocs"
+#define HTTPD_INDEX "index.html"
#define FD_RESERVE 5
#define SERVER_MAX_CLIENTS 1024
void (*)(int, short, void *),
struct timeval *, struct timeval *, void *);
const char *canonicalize_host(const char *, char *, size_t);
+const char *canonicalize_path(const char *, const char *, char *, size_t);
void imsg_event_add(struct imsgev *);
int imsg_compose_event(struct imsgev *, u_int16_t, u_int32_t,
pid_t, int, void *, u_int16_t);
-/* $OpenBSD: server_file.c,v 1.6 2014/07/16 10:25:28 reyk Exp $ */
+/* $OpenBSD: server_file.c,v 1.7 2014/07/23 19:03:56 reyk Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
* XXX Don't expect anything from this code yet,
*/
- strlcpy(path, "/htdocs", sizeof(path));
- if (desc->http_path[0] != '/')
- strlcat(path, "/", sizeof(path));
- strlcat(path, desc->http_path, sizeof(path));
- if (desc->http_path[strlen(desc->http_path) - 1] == '/')
- strlcat(path, "index.html", sizeof(path));
+ if (canonicalize_path(HTTPD_DOCROOT,
+ desc->http_path, path, sizeof(path)) == NULL) {
+ server_abort_http(clt, 404, path);
+ return (-1);
+ }
+
+ /* Prepend default index file */
+ if (path[strlen(path) - 1] == '/' &&
+ strlcat(path, HTTPD_INDEX, sizeof(path)) >= sizeof(path)) {
+ server_abort_http(clt, 404, path);
+ return (-1);
+ }
if (access(path, R_OK) == -1) {
strlcpy(path, desc->http_path, sizeof(path));