summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2018-02-13 17:38:48 +0200
committerSergey Poznyakoff <gray@gnu.org>2018-02-13 17:45:09 +0200
commitef8f3519f2a26877877a315a967b7d953f3e0a33 (patch)
tree03a5f29b443413c3be5c4ad0d787283fa60e57ae
parent8225aeb234795b16827654c1c351544ec224d777 (diff)
downloadfileserv-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.c108
-rw-r--r--src/fileserv.c19
-rw-r--r--src/fileserv.h8
-rw-r--r--src/idx.c5
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);
diff --git a/src/idx.c b/src/idx.c
index 9398aa4..d856dfb 100644
--- a/src/idx.c
+++ b/src/idx.c
@@ -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);

Return to:

Send suggestions and report system problems to the System administrator.