#include "cache.h"
+#include "config.h"
#include "pkt-line.h"
#include "run-command.h"
#include "strbuf.h"
#include "string-list.h"
-#ifndef HOST_NAME_MAX
-#define HOST_NAME_MAX 256
-#endif
-
#ifdef NO_INITGROUPS
#define initgroups(x, y) (0) /* nothing */
#endif
return NULL; /* Fallthrough. Deny by default */
}
-typedef int (*daemon_service_fn)(void);
+typedef int (*daemon_service_fn)(const struct argv_array *env);
struct daemon_service {
const char *name;
const char *config_name;
}
static int run_service(const char *dir, struct daemon_service *service,
- struct hostinfo *hi)
+ struct hostinfo *hi, const struct argv_array *env)
{
const char *path;
int enabled = service->enabled;
*/
signal(SIGTERM, SIG_IGN);
- return service->fn();
+ return service->fn(env);
}
static void copy_to_log(int fd)
fclose(fp);
}
-static int run_service_command(const char **argv)
+static int run_service_command(struct child_process *cld)
{
- struct child_process cld = CHILD_PROCESS_INIT;
-
- cld.argv = argv;
- cld.git_cmd = 1;
- cld.err = -1;
- if (start_command(&cld))
+ argv_array_push(&cld->args, ".");
+ cld->git_cmd = 1;
+ cld->err = -1;
+ if (start_command(cld))
return -1;
close(0);
close(1);
- copy_to_log(cld.err);
+ copy_to_log(cld->err);
- return finish_command(&cld);
+ return finish_command(cld);
}
-static int upload_pack(void)
+static int upload_pack(const struct argv_array *env)
{
- /* Timeout as string */
- char timeout_buf[64];
- const char *argv[] = { "upload-pack", "--strict", NULL, ".", NULL };
+ struct child_process cld = CHILD_PROCESS_INIT;
+ argv_array_pushl(&cld.args, "upload-pack", "--strict", NULL);
+ argv_array_pushf(&cld.args, "--timeout=%u", timeout);
- argv[2] = timeout_buf;
+ argv_array_pushv(&cld.env_array, env->argv);
- snprintf(timeout_buf, sizeof timeout_buf, "--timeout=%u", timeout);
- return run_service_command(argv);
+ return run_service_command(&cld);
}
-static int upload_archive(void)
+static int upload_archive(const struct argv_array *env)
{
- static const char *argv[] = { "upload-archive", ".", NULL };
- return run_service_command(argv);
+ struct child_process cld = CHILD_PROCESS_INIT;
+ argv_array_push(&cld.args, "upload-archive");
+
+ argv_array_pushv(&cld.env_array, env->argv);
+
+ return run_service_command(&cld);
}
-static int receive_pack(void)
+static int receive_pack(const struct argv_array *env)
{
- static const char *argv[] = { "receive-pack", ".", NULL };
- return run_service_command(argv);
+ struct child_process cld = CHILD_PROCESS_INIT;
+ argv_array_push(&cld.args, "receive-pack");
+
+ argv_array_pushv(&cld.env_array, env->argv);
+
+ return run_service_command(&cld);
}
static struct daemon_service daemon_service[] = {
/*
* Read the host as supplied by the client connection.
+ *
+ * Returns a pointer to the character after the NUL byte terminating the host
+ * arguemnt, or 'extra_args' if there is no host arguemnt.
*/
-static void parse_host_arg(struct hostinfo *hi, char *extra_args, int buflen)
+static char *parse_host_arg(struct hostinfo *hi, char *extra_args, int buflen)
{
char *val;
int vallen;
if (extra_args < end && *extra_args)
die("Invalid request");
}
+
+ return extra_args;
+}
+
+static void parse_extra_args(struct hostinfo *hi, struct argv_array *env,
+ char *extra_args, int buflen)
+{
+ const char *end = extra_args + buflen;
+ struct strbuf git_protocol = STRBUF_INIT;
+
+ /* First look for the host argument */
+ extra_args = parse_host_arg(hi, extra_args, buflen);
+
+ /* Look for additional arguments places after a second NUL byte */
+ for (; extra_args < end; extra_args += strlen(extra_args) + 1) {
+ const char *arg = extra_args;
+
+ /*
+ * Parse the extra arguments, adding most to 'git_protocol'
+ * which will be used to set the 'GIT_PROTOCOL' envvar in the
+ * service that will be run.
+ *
+ * If there ends up being a particular arg in the future that
+ * git-daemon needs to parse specificly (like the 'host' arg)
+ * then it can be parsed here and not added to 'git_protocol'.
+ */
+ if (*arg) {
+ if (git_protocol.len > 0)
+ strbuf_addch(&git_protocol, ':');
+ strbuf_addstr(&git_protocol, arg);
+ }
+ }
+
+ if (git_protocol.len > 0)
+ argv_array_pushf(env, GIT_PROTOCOL_ENVIRONMENT "=%s",
+ git_protocol.buf);
+ strbuf_release(&git_protocol);
}
/*
int pktlen, len, i;
char *addr = getenv("REMOTE_ADDR"), *port = getenv("REMOTE_PORT");
struct hostinfo hi;
+ struct argv_array env = ARGV_ARRAY_INIT;
hostinfo_init(&hi);
pktlen--;
}
+ /* parse additional args hidden behind a NUL byte */
if (len != pktlen)
- parse_host_arg(&hi, line + len + 1, pktlen - len - 1);
+ parse_extra_args(&hi, &env, line + len + 1, pktlen - len - 1);
for (i = 0; i < ARRAY_SIZE(daemon_service); i++) {
struct daemon_service *s = &(daemon_service[i]);
* Note: The directory here is probably context sensitive,
* and might depend on the actual service being performed.
*/
- int rc = run_service(arg, s, &hi);
+ int rc = run_service(arg, s, &hi, &env);
hostinfo_clear(&hi);
+ argv_array_clear(&env);
return rc;
}
}
hostinfo_clear(&hi);
+ argv_array_clear(&env);
logerror("Protocol error: '%s'", line);
return -1;
}