]> git.ipfire.org Git - thirdparty/git.git/blobdiff - daemon.c
daemon: use callback to build interpolated path
[thirdparty/git.git] / daemon.c
index 4b0218457610fe994bec256d51b9c01f368383ea..df9768fecc490b681449bdaff17bacb78d257f8c 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -61,6 +61,22 @@ static char *canon_hostname;
 static char *ip_address;
 static char *tcp_port;
 
+static int hostname_lookup_done;
+
+static void lookup_hostname(void);
+
+static const char *get_canon_hostname(void)
+{
+       lookup_hostname();
+       return canon_hostname;
+}
+
+static const char *get_ip_address(void)
+{
+       lookup_hostname();
+       return ip_address;
+}
+
 static void logreport(int priority, const char *err, va_list params)
 {
        if (log_syslog) {
@@ -106,6 +122,46 @@ static void NORETURN daemon_die(const char *err, va_list params)
        exit(1);
 }
 
+static void strbuf_addstr_or_null(struct strbuf *sb, const char *s)
+{
+       if (s)
+               strbuf_addstr(sb, s);
+}
+
+struct expand_path_context {
+       const char *directory;
+};
+
+static size_t expand_path(struct strbuf *sb, const char *placeholder, void *ctx)
+{
+       struct expand_path_context *context = ctx;
+
+       switch (placeholder[0]) {
+       case 'H':
+               strbuf_addstr_or_null(sb, hostname);
+               return 1;
+       case 'C':
+               if (placeholder[1] == 'H') {
+                       strbuf_addstr_or_null(sb, get_canon_hostname());
+                       return 2;
+               }
+               break;
+       case 'I':
+               if (placeholder[1] == 'P') {
+                       strbuf_addstr_or_null(sb, get_ip_address());
+                       return 2;
+               }
+               break;
+       case 'P':
+               strbuf_addstr_or_null(sb, tcp_port);
+               return 1;
+       case 'D':
+               strbuf_addstr(sb, context->directory);
+               return 1;
+       }
+       return 0;
+}
+
 static const char *path_ok(const char *directory)
 {
        static char rpath[PATH_MAX];
@@ -144,14 +200,10 @@ static const char *path_ok(const char *directory)
        }
        else if (interpolated_path && saw_extended_args) {
                struct strbuf expanded_path = STRBUF_INIT;
-               struct strbuf_expand_dict_entry dict[6];
-
-               dict[0].placeholder = "H"; dict[0].value = hostname;
-               dict[1].placeholder = "CH"; dict[1].value = canon_hostname;
-               dict[2].placeholder = "IP"; dict[2].value = ip_address;
-               dict[3].placeholder = "P"; dict[3].value = tcp_port;
-               dict[4].placeholder = "D"; dict[4].value = directory;
-               dict[5].placeholder = NULL; dict[5].value = NULL;
+               struct expand_path_context context;
+
+               context.directory = directory;
+
                if (*dir != '/') {
                        /* Allow only absolute */
                        logerror("'%s': Non-absolute path denied (interpolated-path active)", dir);
@@ -159,7 +211,7 @@ static const char *path_ok(const char *directory)
                }
 
                strbuf_expand(&expanded_path, interpolated_path,
-                               strbuf_expand_dict_cb, &dict);
+                             expand_path, &context);
                strlcpy(interp_path, expanded_path.buf, PATH_MAX);
                strbuf_release(&expanded_path);
                loginfo("Interpolated dir '%s'", interp_path);
@@ -271,8 +323,8 @@ static int run_access_hook(struct daemon_service *service, const char *dir, cons
        *arg++ = service->name;
        *arg++ = path;
        *arg++ = STRARG(hostname);
-       *arg++ = STRARG(canon_hostname);
-       *arg++ = STRARG(ip_address);
+       *arg++ = STRARG(get_canon_hostname());
+       *arg++ = STRARG(get_ip_address());
        *arg++ = STRARG(tcp_port);
        *arg = NULL;
 #undef STRARG
@@ -529,6 +581,7 @@ static void parse_host_arg(char *extra_args, int buflen)
                                }
                                free(hostname);
                                hostname = xstrdup_tolower(host);
+                               hostname_lookup_done = 0;
                        }
 
                        /* On to the next one */
@@ -537,11 +590,14 @@ static void parse_host_arg(char *extra_args, int buflen)
                if (extra_args < end && *extra_args)
                        die("Invalid request");
        }
+}
 
-       /*
-        * Locate canonical hostname and its IP address.
-        */
-       if (hostname) {
+/*
+ * Locate canonical hostname and its IP address.
+ */
+static void lookup_hostname(void)
+{
+       if (!hostname_lookup_done && hostname) {
 #ifndef NO_IPV6
                struct addrinfo hints;
                struct addrinfo *ai;
@@ -589,6 +645,7 @@ static void parse_host_arg(char *extra_args, int buflen)
                        ip_address = xstrdup(addrbuf);
                }
 #endif
+               hostname_lookup_done = 1;
        }
 }