diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2018-02-13 17:38:48 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2018-02-13 17:45:09 +0200 |
commit | ef8f3519f2a26877877a315a967b7d953f3e0a33 (patch) | |
tree | 03a5f29b443413c3be5c4ad0d787283fa60e57ae | |
parent | 8225aeb234795b16827654c1c351544ec224d777 (diff) | |
download | fileserv-ef8f3519f2a26877877a315a967b7d953f3e0a33.tar.gz fileserv-ef8f3519f2a26877877a315a967b7d953f3e0a33.tar.bz2 |
Additional checks for valid file names.
* src/dirconfig.c (set_index_files): Bugfix.
(dirconfig_keyword): New keyword hidden-files.
(dirconfig_free): Free hidden files regexes.
(filename_is_valid, filename_is_special)
(filename_is_hidden): New functions.
* src/fileserv.c (xnrealloc): New function.
(get_file_resp): Additional checks for allowed filenames.
* src/fileserv.h (xnrealloc): new proto.
(DIRCONFIG): New members: hidden_files_rxv, hidden_files_rxc.
(filename_is_special, filename_is_hidden,filename_is_valid): New protos.
* src/idx.c: Skip hidden files.
-rw-r--r-- | src/dirconfig.c | 108 | ||||
-rw-r--r-- | src/fileserv.c | 19 | ||||
-rw-r--r-- | src/fileserv.h | 8 | ||||
-rw-r--r-- | src/idx.c | 5 |
4 files changed, 133 insertions, 7 deletions
diff --git a/src/dirconfig.c b/src/dirconfig.c index f5d1146..0a2a48e 100644 --- a/src/dirconfig.c +++ b/src/dirconfig.c @@ -117,13 +117,59 @@ set_index_files(size_t argc, char **argv, DIRCONFIG *conf, if (argc < 2) return bad_argc(file, line, argv[0]); - conf->index_files = xcalloc(argc, sizeof(conf->index_files)); + conf->index_files = xcalloc(argc, sizeof(conf->index_files[0])); for (i = 1; i < argc; i++) conf->index_files[i-1] = xstrdup(argv[i]); conf->index_files[i-1] = NULL; return 0; } +static void +hidden_files_free(DIRCONFIG *conf) +{ + size_t i; + + for (i = 0; i < conf->hidden_files_rxc; i++) + regfree(&conf->hidden_files_rxv[i]); + conf->hidden_files_rxc = 0; + free(conf->hidden_files_rxv); + conf->hidden_files_rxv = NULL; +} + +static int +set_hidden_files(size_t argc, char **argv, DIRCONFIG *conf, + char const *file, int line) +{ + size_t i; + size_t n = 0; + + if (argc < 2) + return bad_argc(file, line, argv[0]); + + i = 1; + if (strcmp(argv[i], "+") == 0) + i++; + else + hidden_files_free(conf); + + conf->hidden_files_rxv = xnrealloc(conf->hidden_files_rxv, + argc + conf->hidden_files_rxc, + sizeof(conf->hidden_files_rxv[0])); + for (; argv[i]; i++) { + int ec; + ec = regcomp(&conf->hidden_files_rxv[conf->hidden_files_rxc], + argv[i], REG_EXTENDED|REG_NOSUB); + if (ec) { + char buf[512]; + regerror(ec, + &conf->hidden_files_rxv[conf->hidden_files_rxc], + buf, sizeof buf); + error("%s: %s", argv[i], buf); + } else + conf->hidden_files_rxc++; + } +} + struct dirconfig_keyword { char const *ident; int (*setter)(size_t argc, char **argv, DIRCONFIG *conf, @@ -135,6 +181,7 @@ static struct dirconfig_keyword keywords[] = { { "follow", set_follow }, { "listing", set_listing }, { "list-unreadable", set_list_unreadable }, + { "hidden-files", set_hidden_files }, { NULL } }; @@ -226,9 +273,68 @@ dirconfig_free(DIRCONFIG *conf) free(conf->index_files[i]); free(conf->index_files); } + hidden_files_free(conf); free(conf); } } +int +filename_is_valid(char const *name) +{ + enum { a_chr, a_sla, a_dot, a_end, A_MAX }; + enum { s_ini, s_cur, s_sla, s_dot, s_dt2, s_err, s_end, S_MAX = s_end } + state = s_ini; + static char trans[A_MAX][S_MAX] = { + /* ini cur sla dot dt2 err */ + /* chr */ { s_cur, s_cur, s_cur, s_cur, s_cur, s_err }, + /* sla */ { s_sla, s_sla, s_err, s_err, s_err, s_err }, + /* dot */ { s_dot, s_cur, s_dot, s_dt2, s_cur, s_err }, + /* end */ { s_end, s_end, s_end, s_err, s_err, s_err }, + }; + + int c; + while (state != s_err && state != s_end) { + switch (*name++) { + case '/': + c = a_sla; + break; + case '.': + c = a_dot; + break; + case 0: + c = a_end; + break; + default: + c = a_chr; + } + state = trans[c][state]; + } + return state != s_err; +} + +int +filename_is_special(char const *name) +{ + return (name[0] == '.' + && (name[1] == 0 + || (name[1] == '.' && name[2] == 0))); +} + +int +filename_is_hidden(char const *name, DIRCONFIG const *conf) +{ + if (filename_is_special(name) || strcmp(name, dotfile) == 0) + return 1; + + if (conf && conf->hidden_files_rxv) { + size_t i; + for (i = 0; i < conf->hidden_files_rxc; i++) + if (regexec(&conf->hidden_files_rxv[i], name, + 0, NULL, 0) == 0) + return 1; + } + return 0; +} + diff --git a/src/fileserv.c b/src/fileserv.c index a1f6ea3..07e947f 100644 --- a/src/fileserv.c +++ b/src/fileserv.c @@ -90,14 +90,23 @@ xcalloc(size_t nmemb, size_t size) } void * -xrealloc(void *ptr, size_t size) +xnrealloc(void *ptr, size_t nmemb, size_t size) { - ptr = realloc(ptr, size); + if (size < SIZE_T_MAX / nmemb) + ptr = realloc(ptr, nmemb * size); + else + ptr = NULL; if (!ptr) xmalloc_fail(); return ptr; } +void * +xrealloc(void *ptr, size_t size) +{ + return xnrealloc(ptr, 1, size); +} + char * xstrdup(char const *str) { @@ -399,6 +408,9 @@ get_file_resp(struct MHD_Connection *conn, char const *url, FILE_RESP *resp) MHD_HTTP_HEADER_HOST); file_resp_init(resp); + + if (!filename_is_valid(url)) + return MHD_HTTP_NOT_FOUND; map = urimap_find(host, url); if (!map) @@ -409,6 +421,9 @@ get_file_resp(struct MHD_Connection *conn, char const *url, FILE_RESP *resp) resp->conf = dirconfig(resp->file_name, map->dir_len); + if (filename_is_hidden(resp->file_name, resp->conf)) + return MHD_HTTP_NOT_FOUND; + if (S_ISLNK(resp->st.st_mode)) { if (!resp->conf->follow) return MHD_HTTP_FORBIDDEN; diff --git a/src/fileserv.h b/src/fileserv.h index 2ef8cab..ac8058e 100644 --- a/src/fileserv.h +++ b/src/fileserv.h @@ -17,6 +17,7 @@ #include <sys/socket.h> #include <stdlib.h> #include <stdarg.h> +#include <regex.h> #ifndef SIZE_T_MAX # define SIZE_T_MAX ((size_t)-1) @@ -38,6 +39,7 @@ void xmalloc_fail(void); void *xmalloc(size_t s); void *xcalloc(size_t nmemb, size_t size); void *xrealloc(void *ptr, size_t size); +void *xnrealloc(void *ptr, size_t nmemb, size_t size); char *xstrdup(char const *str); void runas(char const *runas_user, char const *runas_group); @@ -58,6 +60,8 @@ typedef struct fileserv_dirconfig { is requested and no index file exists */ int list_unreadable:1; /* List unreadable files */ char **index_files; /* Names of index files */ + regex_t *hidden_files_rxv; + size_t hidden_files_rxc; } DIRCONFIG; #define DIRCONFIG_INITIALIZER { 0, 0, 1, NULL } @@ -90,3 +94,7 @@ INDEX_SORT_COL index_sort_col_from_arg(int c); int index_sort_col_to_arg(INDEX_SORT_COL c); INDEX_SORT_ORD index_sort_ord_from_arg(int c); int index_sort_ord_to_arg(INDEX_SORT_ORD c); + +int filename_is_special(char const *name); +int filename_is_hidden(char const *name, DIRCONFIG const *conf); +int filename_is_valid(char const *name); @@ -307,9 +307,7 @@ idxlist_scan(IDXLIST *idx_list, char const *path, DIRCONFIG const *conf) char *name; struct stat st; - if (ent->d_name[0] == '.' - && (ent->d_name[1] == 0 - || (ent->d_name[1] == '.' && ent->d_name[2] == 0))) + if (filename_is_hidden(ent->d_name, conf)) continue; name = catfile(path, ent->d_name); @@ -500,7 +498,6 @@ static int node_loop_eval(INDEX_NODE *node, EVAL_ENV *env) { while (env->ent) { - //FIXME: set variables? if (node_list_eval(&node->v.loop, env)) return -1; env->ent = STAILQ_NEXT(env->ent, next); |