static int run_access_hook(struct daemon_service *service, const char *dir, const char *path, struct hostinfo *hi) { struct child_process child = CHILD_PROCESS_INIT; struct strbuf buf = STRBUF_INIT; const char *argv[8]; const char **arg = argv; char *eol; int seen_errors = 0; *arg++ = access_hook; *arg++ = service->name; *arg++ = path; *arg++ = hi->hostname.buf; *arg++ = get_canon_hostname(hi); *arg++ = get_ip_address(hi); *arg++ = hi->tcp_port.buf; *arg = NULL; 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; int enabled = service->enabled; loginfo("Request %s for '%s'", service->name, dir); if (!enabled && !service->overridable) { logerror("'%s': service not enabled.", service->name); errno = EACCES; return daemon_error(dir, "service not enabled"); } if (!(path = path_ok(dir))) return daemon_error(dir, "no such repository"); /* * Security on the cheap. * * We want a readable HEAD, usable "objects" directory, and * a "git-daemon-export-ok" flag that says that the other side * is ok with us doing this. * * path_ok() uses enter_repo() and does whitelist checking. * We only need to make sure the repository is exported. */ if (!export_all_trees && access("git-daemon-export-ok", F_OK)) { logerror("'%s': repository not exported.", path); errno = EACCES; return daemon_error(dir, "repository not exported"); } if (service->overridable) { service_looking_at = service; service_enabled = -1; git_config(git_daemon_config, NULL); if (0 <= service_enabled) enabled = service_enabled; } if (!enabled) { logerror("'%s': service not enabled for '%s'", service->name, path); errno = EACCES; return daemon_error(dir, "service not enabled"); } /* * 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. */ signal(SIGTERM, SIG_IGN); return service->fn(); }
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; }