untracked cache: save to an index extension
[gitweb.git] / daemon.c
index df9768fecc490b681449bdaff17bacb78d257f8c..c3edd960ec5bf686b66fa55dcfea712e455fe772 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -282,23 +282,6 @@ struct daemon_service {
        int overridable;
 };
 
-static struct daemon_service *service_looking_at;
-static int service_enabled;
-
-static int git_daemon_config(const char *var, const char *value, void *cb)
-{
-       const char *service;
-
-       if (skip_prefix(var, "daemon.", &service) &&
-           !strcmp(service, service_looking_at->config_name)) {
-               service_enabled = git_config_bool(var, value);
-               return 0;
-       }
-
-       /* we are not interested in parsing any other configuration here */
-       return 0;
-}
-
 static int daemon_error(const char *dir, const char *msg)
 {
        if (!informative_errors)
@@ -311,7 +294,7 @@ static const char *access_hook;
 
 static int run_access_hook(struct daemon_service *service, const char *dir, const char *path)
 {
-       struct child_process child;
+       struct child_process child = CHILD_PROCESS_INIT;
        struct strbuf buf = STRBUF_INIT;
        const char *argv[8];
        const char **arg = argv;
@@ -329,7 +312,6 @@ static int run_access_hook(struct daemon_service *service, const char *dir, cons
        *arg = NULL;
 #undef STRARG
 
-       memset(&child, 0, sizeof(child));
        child.use_shell = 1;
        child.argv = argv;
        child.no_stdin = 1;
@@ -376,6 +358,7 @@ static int run_service(const char *dir, struct daemon_service *service)
 {
        const char *path;
        int enabled = service->enabled;
+       struct strbuf var = STRBUF_INIT;
 
        loginfo("Request %s for '%s'", service->name, dir);
 
@@ -406,11 +389,9 @@ static int run_service(const char *dir, struct daemon_service *service)
        }
 
        if (service->overridable) {
-               service_looking_at = service;
-               service_enabled = -1;
-               git_config(git_daemon_config, NULL);
-               if (0 <= service_enabled)
-                       enabled = service_enabled;
+               strbuf_addf(&var, "daemon.%s", service->config_name);
+               git_config_get_bool(var.buf, &enabled);
+               strbuf_release(&var);
        }
        if (!enabled) {
                logerror("'%s': service not enabled for '%s'",
@@ -458,9 +439,8 @@ static void copy_to_log(int fd)
 
 static int run_service_command(const char **argv)
 {
-       struct child_process cld;
+       struct child_process cld = CHILD_PROCESS_INIT;
 
-       memset(&cld, 0, sizeof(cld));
        cld.argv = argv;
        cld.git_cmd = 1;
        cld.err = -1;
@@ -556,6 +536,45 @@ static void parse_host_and_port(char *hostport, char **host,
        }
 }
 
+/*
+ * Sanitize a string from the client so that it's OK to be inserted into a
+ * filesystem path. Specifically, we disallow slashes, runs of "..", and
+ * trailing and leading dots, which means that the client cannot escape
+ * our base path via ".." traversal.
+ */
+static void sanitize_client_strbuf(struct strbuf *out, const char *in)
+{
+       for (; *in; in++) {
+               if (*in == '/')
+                       continue;
+               if (*in == '.' && (!out->len || out->buf[out->len - 1] == '.'))
+                       continue;
+               strbuf_addch(out, *in);
+       }
+
+       while (out->len && out->buf[out->len - 1] == '.')
+               strbuf_setlen(out, out->len - 1);
+}
+
+static char *sanitize_client(const char *in)
+{
+       struct strbuf out = STRBUF_INIT;
+       sanitize_client_strbuf(&out, in);
+       return strbuf_detach(&out, NULL);
+}
+
+/*
+ * Like sanitize_client, but we also perform any canonicalization
+ * to make life easier on the admin.
+ */
+static char *canonicalize_client(const char *in)
+{
+       struct strbuf out = STRBUF_INIT;
+       sanitize_client_strbuf(&out, in);
+       strbuf_tolower(&out);
+       return strbuf_detach(&out, NULL);
+}
+
 /*
  * Read the host as supplied by the client connection.
  */
@@ -577,10 +596,10 @@ static void parse_host_arg(char *extra_args, int buflen)
                                parse_host_and_port(val, &host, &port);
                                if (port) {
                                        free(tcp_port);
-                                       tcp_port = xstrdup(port);
+                                       tcp_port = sanitize_client(port);
                                }
                                free(hostname);
-                               hostname = xstrdup_tolower(host);
+                               hostname = canonicalize_client(host);
                                hostname_lookup_done = 0;
                        }
 
@@ -617,8 +636,9 @@ static void lookup_hostname(void)
                        ip_address = xstrdup(addrbuf);
 
                        free(canon_hostname);
-                       canon_hostname = xstrdup(ai->ai_canonname ?
-                                                ai->ai_canonname : ip_address);
+                       canon_hostname = ai->ai_canonname ?
+                               sanitize_client(ai->ai_canonname) :
+                               xstrdup(ip_address);
 
                        freeaddrinfo(ai);
                }
@@ -640,7 +660,7 @@ static void lookup_hostname(void)
                                  addrbuf, sizeof(addrbuf));
 
                        free(canon_hostname);
-                       canon_hostname = xstrdup(hent->h_name);
+                       canon_hostname = sanitize_client(hent->h_name);
                        free(ip_address);
                        ip_address = xstrdup(addrbuf);
                }
@@ -791,7 +811,7 @@ static void check_dead_children(void)
 static char **cld_argv;
 static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen)
 {
-       struct child_process cld = { NULL };
+       struct child_process cld = CHILD_PROCESS_INIT;
        char addrbuf[300] = "REMOTE_ADDR=", portbuf[300];
        char *env[] = { addrbuf, portbuf, NULL };