#include "cache.h"
#include "pkt-line.h"
#include "exec_cmd.h"
+#include "run-command.h"
+#include "strbuf.h"
#include <syslog.h>
}
}
+__attribute__((format (printf, 1, 2)))
static void logerror(const char *err, ...)
{
va_list params;
va_end(params);
}
+__attribute__((format (printf, 1, 2)))
static void loginfo(const char *err, ...)
{
va_list params;
exit(1);
}
-static int avoid_alias(char *p)
-{
- int sl, ndot;
-
- /*
- * This resurrects the belts and suspenders paranoia check by HPA
- * done in <435560F7.4080006@zytor.com> thread, now enter_repo()
- * does not do getcwd() based path canonicalizations.
- *
- * sl becomes true immediately after seeing '/' and continues to
- * be true as long as dots continue after that without intervening
- * non-dot character.
- */
- if (!p || (*p != '/' && *p != '~'))
- return -1;
- sl = 1; ndot = 0;
- p++;
-
- while (1) {
- char ch = *p++;
- if (sl) {
- if (ch == '.')
- ndot++;
- else if (ch == '/') {
- if (ndot < 3)
- /* reject //, /./ and /../ */
- return -1;
- ndot = 0;
- }
- else if (ch == 0) {
- if (0 < ndot && ndot < 3)
- /* reject /.$ and /..$ */
- return -1;
- return 0;
- }
- else
- sl = ndot = 0;
- }
- else if (ch == 0)
- return 0;
- else if (ch == '/') {
- sl = 1;
- ndot = 0;
- }
- }
-}
-
static char *path_ok(char *directory)
{
static char rpath[PATH_MAX];
dir = directory;
- if (avoid_alias(dir)) {
+ if (daemon_avoid_alias(dir)) {
logerror("'%s': aliased", dir);
return NULL;
}
return service->fn();
}
+static void copy_to_log(int fd)
+{
+ struct strbuf line = STRBUF_INIT;
+ FILE *fp;
+
+ fp = fdopen(fd, "r");
+ if (fp == NULL) {
+ logerror("fdopen of error channel failed");
+ close(fd);
+ return;
+ }
+
+ while (strbuf_getline(&line, fp, '\n') != EOF) {
+ logerror("%s", line.buf);
+ strbuf_setlen(&line, 0);
+ }
+
+ strbuf_release(&line);
+ fclose(fp);
+}
+
+static int run_service_command(const char **argv)
+{
+ struct child_process cld;
+
+ memset(&cld, 0, sizeof(cld));
+ cld.argv = argv;
+ cld.git_cmd = 1;
+ cld.err = -1;
+ if (start_command(&cld))
+ return -1;
+
+ close(0);
+ close(1);
+
+ copy_to_log(cld.err);
+
+ return finish_command(&cld);
+}
+
static int upload_pack(void)
{
/* Timeout as string */
char timeout_buf[64];
+ const char *argv[] = { "upload-pack", "--strict", timeout_buf, ".", NULL };
snprintf(timeout_buf, sizeof timeout_buf, "--timeout=%u", timeout);
-
- /* git-upload-pack only ever reads stuff, so this is safe */
- execl_git_cmd("upload-pack", "--strict", timeout_buf, ".", NULL);
- return -1;
+ return run_service_command(argv);
}
static int upload_archive(void)
{
- execl_git_cmd("upload-archive", ".", NULL);
- return -1;
+ static const char *argv[] = { "upload-archive", ".", NULL };
+ return run_service_command(argv);
}
static int receive_pack(void)
{
- execl_git_cmd("receive-pack", ".", NULL);
- return -1;
+ static const char *argv[] = { "receive-pack", ".", NULL };
+ return run_service_command(argv);
}
static struct daemon_service daemon_service[] = {
}
/*
- * Separate the "extra args" information as supplied by the client connection.
+ * Read the host as supplied by the client connection.
*/
-static void parse_extra_args(char *extra_args, int buflen)
+static void parse_host_arg(char *extra_args, int buflen)
{
char *val;
int vallen;
char *end = extra_args + buflen;
- while (extra_args < end && *extra_args) {
+ if (extra_args < end && *extra_args) {
saw_extended_args = 1;
if (strncasecmp("host=", extra_args, 5) == 0) {
val = extra_args + 5;
/* On to the next one */
extra_args = val + vallen;
}
+ if (extra_args < end && *extra_args)
+ die("Invalid request");
}
/*
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME;
- gai = getaddrinfo(hostname, 0, &hints, &ai);
+ gai = getaddrinfo(hostname, NULL, &hints, &ai);
if (!gai) {
struct sockaddr_in *sin_addr = (void *)ai->ai_addr;
hostname = canon_hostname = ip_address = tcp_port = NULL;
if (len != pktlen)
- parse_extra_args(line + len + 1, pktlen - len - 1);
+ parse_host_arg(line + len + 1, pktlen - len - 1);
for (i = 0; i < ARRAY_SIZE(daemon_service); i++) {
struct daemon_service *s = &(daemon_service[i]);
case ECONNABORTED:
continue;
default:
- die("accept returned %s", strerror(errno));
+ die_errno("accept returned");
}
}
handle(incoming, (struct sockaddr *)&ss, sslen);
while (fd != -1 && fd < 2)
fd = dup(fd);
if (fd == -1)
- die("open /dev/null or dup failed: %s", strerror(errno));
+ die_errno("open /dev/null or dup failed");
if (fd > 2)
close(fd);
}
case 0:
break;
case -1:
- die("fork failed: %s", strerror(errno));
+ die_errno("fork failed");
default:
exit(0);
}
if (setsid() == -1)
- die("setsid failed: %s", strerror(errno));
+ die_errno("setsid failed");
close(0);
close(1);
close(2);
{
FILE *f = fopen(path, "w");
if (!f)
- die("cannot open pid file %s: %s", path, strerror(errno));
+ die_errno("cannot open pid file '%s'", path);
if (fprintf(f, "%"PRIuMAX"\n", (uintmax_t) getpid()) < 0 || fclose(f) != 0)
- die("failed to write pid file %s: %s", path, strerror(errno));
+ die_errno("failed to write pid file '%s'", path);
}
static int serve(char *listen_addr, int listen_port, struct passwd *pass, gid_t gid)
socklen_t slen = sizeof(ss);
if (!freopen("/dev/null", "w", stderr))
- die("failed to redirect stderr to /dev/null: %s",
- strerror(errno));
+ die_errno("failed to redirect stderr to /dev/null");
if (getpeername(0, peer, &slen))
peer = NULL;