diff options
Diffstat (limited to 'daemon.c')
-rw-r--r-- | daemon.c | 107 |
1 files changed, 85 insertions, 22 deletions
@@ -9,10 +9,6 @@ #define HOST_NAME_MAX 256 #endif -#ifndef NI_MAXSERV -#define NI_MAXSERV 32 -#endif - #ifdef NO_INITGROUPS #define initgroups(x, y) (0) /* nothing */ #endif @@ -30,6 +26,7 @@ static const char daemon_usage[] = " [--interpolated-path=<path>]\n" " [--reuseaddr] [--pid-file=<file>]\n" " [--(enable|disable|allow-override|forbid-override)=<service>]\n" +" [--access-hook=<path>]\n" " [--inetd | [--listen=<host_or_ipaddr>] [--port=<n>]\n" " [--detach] [--user=<user> [--group=<group>]]\n" " [<directory>...]"; @@ -256,6 +253,71 @@ static int daemon_error(const char *dir, const char *msg) return -1; } +static char *access_hook; + +static int run_access_hook(struct daemon_service *service, const char *dir, const char *path) +{ + struct child_process child; + struct strbuf buf = STRBUF_INIT; + const char *argv[8]; + const char **arg = argv; + char *eol; + int seen_errors = 0; + +#define STRARG(x) ((x) ? (x) : "") + *arg++ = access_hook; + *arg++ = service->name; + *arg++ = path; + *arg++ = STRARG(hostname); + *arg++ = STRARG(canon_hostname); + *arg++ = STRARG(ip_address); + *arg++ = STRARG(tcp_port); + *arg = NULL; +#undef STRARG + + memset(&child, 0, sizeof(child)); + child.use_shell = 1; + child.argv = argv; + child.no_stdin = 1; + child.no_stderr = 1; + child.out = -1; + if (start_command(&child)) { + logerror("daemon access hook '%s' failed to start", + access_hook); + goto error_return; + } + if (strbuf_read(&buf, child.out, 0) < 0) { + logerror("failed to read from pipe to daemon access hook '%s'", + access_hook); + strbuf_reset(&buf); + seen_errors = 1; + } + if (close(child.out) < 0) { + logerror("failed to close pipe to daemon access hook '%s'", + access_hook); + seen_errors = 1; + } + if (finish_command(&child)) + seen_errors = 1; + + if (!seen_errors) { + strbuf_release(&buf); + return 0; + } + +error_return: + strbuf_ltrim(&buf); + if (!buf.len) + strbuf_addstr(&buf, "service rejected"); + eol = strchr(buf.buf, '\n'); + if (eol) + *eol = '\0'; + errno = EACCES; + daemon_error(dir, buf.buf); + strbuf_release(&buf); + return -1; +} + static int run_service(char *dir, struct daemon_service *service) { const char *path; @@ -304,6 +366,13 @@ static int run_service(char *dir, struct daemon_service *service) } /* + * Optionally, a hook can choose to deny access to the + * repository depending on the phase of the moon. + */ + if (access_hook && run_access_hook(service, dir, path)) + return -1; + + /* * We'll ignore SIGTERM from now on, we have a * good client. */ @@ -531,7 +600,7 @@ static void parse_host_arg(char *extra_args, int buflen) static int execute(void) { - static char line[1000]; + char *line = packet_buffer; int pktlen, len, i; char *addr = getenv("REMOTE_ADDR"), *port = getenv("REMOTE_PORT"); @@ -539,7 +608,7 @@ static int execute(void) loginfo("Connection from %s:%s", addr, port); alarm(init_timeout ? init_timeout : timeout); - pktlen = packet_read_line(0, line, sizeof(line)); + pktlen = packet_read(0, NULL, NULL, packet_buffer, sizeof(packet_buffer), 0); alarm(0); len = strlen(line); @@ -691,7 +760,7 @@ static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen) snprintf(portbuf, sizeof(portbuf), "REMOTE_PORT=%d", ntohs(sin_addr->sin_port)); #ifndef NO_IPV6 - } else if (addr && addr->sa_family == AF_INET6) { + } else if (addr->sa_family == AF_INET6) { struct sockaddr_in6 *sin6_addr = (void *) addr; char *buf = addrbuf + 12; @@ -978,18 +1047,6 @@ static int service_loop(struct socketlist *socklist) } } -/* if any standard file descriptor is missing open it to /dev/null */ -static void sanitize_stdfds(void) -{ - int fd = open("/dev/null", O_RDWR, 0); - while (fd != -1 && fd < 2) - fd = dup(fd); - if (fd == -1) - die_errno("open /dev/null or dup failed"); - if (fd > 2) - close(fd); -} - #ifdef NO_POSIX_GOODIES struct credentials; @@ -1086,6 +1143,8 @@ static int serve(struct string_list *listen_addr, int listen_port, drop_privileges(cred); + loginfo("Ready to rumble"); + return service_loop(&socklist); } @@ -1099,6 +1158,8 @@ int main(int argc, char **argv) struct credentials *cred = NULL; int i; + git_setup_gettext(); + git_extract_argv0_path(argv[0]); for (i = 1; i < argc; i++) { @@ -1138,6 +1199,10 @@ int main(int argc, char **argv) export_all_trees = 1; continue; } + if (!prefixcmp(arg, "--access-hook=")) { + access_hook = arg + 14; + continue; + } if (!prefixcmp(arg, "--timeout=")) { timeout = atoi(arg+10); continue; @@ -1268,10 +1333,8 @@ int main(int argc, char **argv) if (inetd_mode || serve_mode) return execute(); - if (detach) { + if (detach) daemonize(); - loginfo("Ready to rumble"); - } else sanitize_stdfds(); |