diff options
author | Florian Obser <florian@cvs.openbsd.org> | 2015-02-10 08:12:30 +0000 |
---|---|---|
committer | Florian Obser <florian@cvs.openbsd.org> | 2015-02-10 08:12:30 +0000 |
commit | f5ccda6996b82c0129c5eb8249f0efbb75ff8b5a (patch) | |
tree | f1f0a4f6a235912576ac456ddbdf5f2e452af536 /usr.sbin | |
parent | b5c2159defa1cc30b5386914331a73ed5e49c874 (diff) |
Encode directory listings.
Problem pointed out by remco AT d-compu.dyndns.org some time ago.
Input / OK reyk@
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/httpd/httpd.c | 58 | ||||
-rw-r--r-- | usr.sbin/httpd/httpd.h | 4 | ||||
-rw-r--r-- | usr.sbin/httpd/server_file.c | 21 |
3 files changed, 77 insertions, 6 deletions
diff --git a/usr.sbin/httpd/httpd.c b/usr.sbin/httpd/httpd.c index f640dc2bfbd..273e0f9c9fb 100644 --- a/usr.sbin/httpd/httpd.c +++ b/usr.sbin/httpd/httpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: httpd.c,v 1.32 2015/02/08 00:00:59 reyk Exp $ */ +/* $OpenBSD: httpd.c,v 1.33 2015/02/10 08:12:29 florian Exp $ */ /* * Copyright (c) 2014 Reyk Floeter <reyk@openbsd.org> @@ -671,6 +671,62 @@ path_info(char *path) return (p - start); } +char* +escape_uri(const char *src) +{ + static char hex[] = "0123456789ABCDEF"; + char *dp, *dst; + unsigned char c; + + /* We need 3 times the memory if every letter is encoded. */ + if ((dst = calloc(3, strlen(src) + 1)) == NULL) + return NULL; + + for (dp = dst; *src != 0; src++) { + c = (unsigned char) *src; + if (c == ' ' || c == '#' || c == '%' || c == '?' || c == '"' || + c == '&' || c == '<' || c <= 0x1f || c >= 0x7f) { + *dp++ = '%'; + *dp++ = hex[c >> 4]; + *dp++ = hex[c & 0x0f]; + } else + *dp++ = *src; + } + return (dst); +} + +char* +escape_html(const char* src) +{ + char *dp, *dst; + + /* We need 5 times the memory if every letter is "<" or ">". */ + if ((dst = calloc(5, strlen(src) + 1)) == NULL) + return NULL; + + for (dp = dst; *src != 0; src++) { + if (*src == '<') { + *dp++ = '&'; + *dp++ = 'l'; + *dp++ = 't'; + *dp++ = ';'; + } else if (*src == '>') { + *dp++ = '&'; + *dp++ = 'g'; + *dp++ = 't'; + *dp++ = ';'; + } else if (*src == '&') { + *dp++ = '&'; + *dp++ = 'a'; + *dp++ = 'm'; + *dp++ = 'p'; + *dp++ = ';'; + } else + *dp++ = *src; + } + return (dst); +} + void socket_rlimit(int maxfd) { diff --git a/usr.sbin/httpd/httpd.h b/usr.sbin/httpd/httpd.h index 98096c9ac39..625c81077a9 100644 --- a/usr.sbin/httpd/httpd.h +++ b/usr.sbin/httpd/httpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: httpd.h,v 1.77 2015/02/07 23:56:02 reyk Exp $ */ +/* $OpenBSD: httpd.h,v 1.78 2015/02/10 08:12:29 florian Exp $ */ /* * Copyright (c) 2006 - 2015 Reyk Floeter <reyk@openbsd.org> @@ -587,6 +587,8 @@ const char *url_decode(char *); const char *canonicalize_host(const char *, char *, size_t); const char *canonicalize_path(const char *, char *, size_t); size_t path_info(char *); +char *escape_uri(const char *); +char *escape_html(const char *); 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); diff --git a/usr.sbin/httpd/server_file.c b/usr.sbin/httpd/server_file.c index b24f0c07e99..199bf07c3a4 100644 --- a/usr.sbin/httpd/server_file.c +++ b/usr.sbin/httpd/server_file.c @@ -1,4 +1,4 @@ -/* $OpenBSD: server_file.c,v 1.49 2015/02/08 00:00:59 reyk Exp $ */ +/* $OpenBSD: server_file.c,v 1.50 2015/02/10 08:12:29 florian Exp $ */ /* * Copyright (c) 2006 - 2015 Reyk Floeter <reyk@openbsd.org> @@ -274,6 +274,7 @@ server_file_index(struct httpd *env, struct client *clt, struct stat *st) struct evbuffer *evb = NULL; struct media_type *media; const char *stripped, *style; + char *escapeduri, *escapedhtml, *escapedpath; struct tm tm; time_t t, dir_mtime; @@ -304,6 +305,9 @@ server_file_index(struct httpd *env, struct client *clt, struct stat *st) /* Indicate failure but continue going through the list */ skip = 0; + if ((escapedpath = escape_html(desc->http_path)) == NULL) + goto fail; + /* A CSS stylesheet allows minimal customization by the user */ style = "body { background-color: white; color: black; font-family: " "sans-serif; }\nhr { border: 0; border-bottom: 1px dashed; }\n"; @@ -318,9 +322,11 @@ server_file_index(struct httpd *env, struct client *clt, struct stat *st) "<body>\n" "<h1>Index of %s</h1>\n" "<hr>\n<pre>\n", - desc->http_path, style, desc->http_path) == -1) + escapedpath, style, escapedpath) == -1) skip = 1; + free(escapedpath); + for (i = 0; i < namesize; i++) { dp = namelist[i]; @@ -335,6 +341,11 @@ server_file_index(struct httpd *env, struct client *clt, struct stat *st) strftime(tmstr, sizeof(tmstr), "%d-%h-%Y %R", &tm); namewidth = 51 - strlen(dp->d_name); + if ((escapeduri = escape_uri(dp->d_name)) == NULL) + goto fail; + if ((escapedhtml = escape_html(dp->d_name)) == NULL) + goto fail; + if (dp->d_name[0] == '.' && !(dp->d_name[1] == '.' && dp->d_name[2] == '\0')) { /* ignore hidden files starting with a dot */ @@ -342,17 +353,19 @@ server_file_index(struct httpd *env, struct client *clt, struct stat *st) namewidth -= 1; /* trailing slash */ if (evbuffer_add_printf(evb, "<a href=\"%s\">%s/</a>%*s%s%20s\n", - dp->d_name, dp->d_name, + escapeduri, escapedhtml, MAXIMUM(namewidth, 0), " ", tmstr, "-") == -1) skip = 1; } else if (S_ISREG(st->st_mode)) { if (evbuffer_add_printf(evb, "<a href=\"%s\">%s</a>%*s%s%20llu\n", - dp->d_name, dp->d_name, + escapeduri, escapedhtml, MAXIMUM(namewidth, 0), " ", tmstr, st->st_size) == -1) skip = 1; } + free(escapeduri); + free(escapedhtml); free(dp); } free(namelist); |