int main(int argc, char **argv) { int listen_port = 0; struct string_list listen_addr = STRING_LIST_INIT_NODUP; int serve_mode = 0, inetd_mode = 0; const char *pid_file = NULL, *user_name = NULL, *group_name = NULL; int detach = 0; struct credentials *cred = NULL; int i; git_setup_gettext(); git_extract_argv0_path(argv[0]); for (i = 1; i < argc; i++) { char *arg = argv[i]; if (!prefixcmp(arg, "--listen=")) { string_list_append(&listen_addr, xstrdup_tolower(arg + 9)); continue; } if (!prefixcmp(arg, "--port=")) { char *end; unsigned long n; n = strtoul(arg+7, &end, 0); if (arg[7] && !*end) { listen_port = n; continue; } } if (!strcmp(arg, "--serve")) { serve_mode = 1; continue; } if (!strcmp(arg, "--inetd")) { inetd_mode = 1; log_syslog = 1; continue; } if (!strcmp(arg, "--verbose")) { verbose = 1; continue; } if (!strcmp(arg, "--syslog")) { log_syslog = 1; continue; } if (!strcmp(arg, "--export-all")) { export_all_trees = 1; continue; } if (!prefixcmp(arg, "--access-hook=")) { access_hook = arg + 14; continue; } if (!prefixcmp(arg, "--timeout=")) { timeout = atoi(arg+10); continue; } if (!prefixcmp(arg, "--init-timeout=")) { init_timeout = atoi(arg+15); continue; } if (!prefixcmp(arg, "--max-connections=")) { max_connections = atoi(arg+18); if (max_connections < 0) max_connections = 0; /* unlimited */ continue; } if (!strcmp(arg, "--strict-paths")) { strict_paths = 1; continue; } if (!prefixcmp(arg, "--base-path=")) { base_path = arg+12; continue; } if (!strcmp(arg, "--base-path-relaxed")) { base_path_relaxed = 1; continue; } if (!prefixcmp(arg, "--interpolated-path=")) { interpolated_path = arg+20; continue; } if (!strcmp(arg, "--reuseaddr")) { reuseaddr = 1; continue; } if (!strcmp(arg, "--user-path")) { user_path = ""; continue; } if (!prefixcmp(arg, "--user-path=")) { user_path = arg + 12; continue; } if (!prefixcmp(arg, "--pid-file=")) { pid_file = arg + 11; continue; } if (!strcmp(arg, "--detach")) { detach = 1; log_syslog = 1; continue; } if (!prefixcmp(arg, "--user="******"--group=")) { group_name = arg + 8; continue; } if (!prefixcmp(arg, "--enable=")) { enable_service(arg + 9, 1); continue; } if (!prefixcmp(arg, "--disable=")) { enable_service(arg + 10, 0); continue; } if (!prefixcmp(arg, "--allow-override=")) { make_service_overridable(arg + 17, 1); continue; } if (!prefixcmp(arg, "--forbid-override=")) { make_service_overridable(arg + 18, 0); continue; } if (!prefixcmp(arg, "--informative-errors")) { informative_errors = 1; continue; } if (!prefixcmp(arg, "--no-informative-errors")) { informative_errors = 0; continue; } if (!strcmp(arg, "--")) { ok_paths = &argv[i+1]; break; } else if (arg[0] != '-') { ok_paths = &argv[i]; break; } usage(daemon_usage); } if (log_syslog) { openlog("git-daemon", LOG_PID, LOG_DAEMON); set_die_routine(daemon_die); } else /* avoid splitting a message in the middle */ setvbuf(stderr, NULL, _IOFBF, 4096); if (inetd_mode && (detach || group_name || user_name)) die("--detach, --user and --group are incompatible with --inetd"); if (inetd_mode && (listen_port || (listen_addr.nr > 0))) die("--listen= and --port= are incompatible with --inetd"); else if (listen_port == 0) listen_port = DEFAULT_GIT_PORT; if (group_name && !user_name) die("--group supplied without --user"); if (user_name) cred = prepare_credentials(user_name, group_name); if (strict_paths && (!ok_paths || !*ok_paths)) die("option --strict-paths requires a whitelist"); if (base_path && !is_directory(base_path)) die("base-path '%s' does not exist or is not a directory", base_path); if (inetd_mode) { if (!freopen("/dev/null", "w", stderr)) die_errno("failed to redirect stderr to /dev/null"); } if (inetd_mode || serve_mode) return execute(); if (detach) daemonize(); else sanitize_stdfds(); if (pid_file) store_pid(pid_file); /* prepare argv for serving-processes */ cld_argv = xmalloc(sizeof (char *) * (argc + 2)); cld_argv[0] = argv[0]; /* git-daemon */ cld_argv[1] = "--serve"; for (i = 1; i < argc; ++i) cld_argv[i+1] = argv[i]; cld_argv[argc+1] = NULL; return serve(&listen_addr, listen_port, cred); }
/* * Read the host as supplied by the client connection. */ static void parse_host_arg(char *extra_args, int buflen) { char *val; int vallen; char *end = extra_args + buflen; if (extra_args < end && *extra_args) { saw_extended_args = 1; if (strncasecmp("host=", extra_args, 5) == 0) { val = extra_args + 5; vallen = strlen(val) + 1; if (*val) { /* Split <host>:<port> at colon. */ char *host; char *port; parse_host_and_port(val, &host, &port); if (port) { free(tcp_port); tcp_port = xstrdup(port); } free(hostname); hostname = xstrdup_tolower(host); } /* On to the next one */ extra_args = val + vallen; } if (extra_args < end && *extra_args) die("Invalid request"); } /* * Locate canonical hostname and its IP address. */ if (hostname) { #ifndef NO_IPV6 struct addrinfo hints; struct addrinfo *ai; int gai; static char addrbuf[HOST_NAME_MAX + 1]; memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_CANONNAME; gai = getaddrinfo(hostname, NULL, &hints, &ai); if (!gai) { struct sockaddr_in *sin_addr = (void *)ai->ai_addr; inet_ntop(AF_INET, &sin_addr->sin_addr, addrbuf, sizeof(addrbuf)); free(ip_address); ip_address = xstrdup(addrbuf); free(canon_hostname); canon_hostname = xstrdup(ai->ai_canonname ? ai->ai_canonname : ip_address); freeaddrinfo(ai); } #else struct hostent *hent; struct sockaddr_in sa; char **ap; static char addrbuf[HOST_NAME_MAX + 1]; hent = gethostbyname(hostname); ap = hent->h_addr_list; memset(&sa, 0, sizeof sa); sa.sin_family = hent->h_addrtype; sa.sin_port = htons(0); memcpy(&sa.sin_addr, *ap, hent->h_length); inet_ntop(hent->h_addrtype, &sa.sin_addr, addrbuf, sizeof(addrbuf)); free(canon_hostname); canon_hostname = xstrdup(hent->h_name); free(ip_address); ip_address = xstrdup(addrbuf); #endif } }
int main(int argc, char **argv) { int listen_port = 0; struct string_list listen_addr = STRING_LIST_INIT_NODUP; int inetd_mode = 0; const char *pid_file = NULL, *user_name = NULL, *group_name = NULL; int detach = 0; struct passwd *pass = NULL; struct group *group; gid_t gid = 0; int i; git_extract_argv0_path(argv[0]); for (i = 1; i < argc; i++) { char *arg = argv[i]; if (!prefixcmp(arg, "--listen=")) { string_list_append(&listen_addr, xstrdup_tolower(arg + 9)); continue; } if (!prefixcmp(arg, "--port=")) { char *end; unsigned long n; n = strtoul(arg+7, &end, 0); if (arg[7] && !*end) { listen_port = n; continue; } } if (!strcmp(arg, "--inetd")) { inetd_mode = 1; log_syslog = 1; continue; } if (!strcmp(arg, "--verbose")) { verbose = 1; continue; } if (!strcmp(arg, "--syslog")) { log_syslog = 1; continue; } if (!strcmp(arg, "--export-all")) { export_all_trees = 1; continue; } if (!prefixcmp(arg, "--timeout=")) { timeout = atoi(arg+10); continue; } if (!prefixcmp(arg, "--init-timeout=")) { init_timeout = atoi(arg+15); continue; } if (!prefixcmp(arg, "--max-connections=")) { max_connections = atoi(arg+18); if (max_connections < 0) max_connections = 0; /* unlimited */ continue; } if (!strcmp(arg, "--strict-paths")) { strict_paths = 1; continue; } if (!prefixcmp(arg, "--base-path=")) { base_path = arg+12; continue; } if (!strcmp(arg, "--base-path-relaxed")) { base_path_relaxed = 1; continue; } if (!prefixcmp(arg, "--interpolated-path=")) { interpolated_path = arg+20; continue; } if (!strcmp(arg, "--reuseaddr")) { reuseaddr = 1; continue; } if (!strcmp(arg, "--user-path")) { user_path = ""; continue; } if (!prefixcmp(arg, "--user-path=")) { user_path = arg + 12; continue; } if (!prefixcmp(arg, "--pid-file=")) { pid_file = arg + 11; continue; } if (!strcmp(arg, "--detach")) { detach = 1; log_syslog = 1; continue; } if (!prefixcmp(arg, "--user="******"--group=")) { group_name = arg + 8; continue; } if (!prefixcmp(arg, "--enable=")) { enable_service(arg + 9, 1); continue; } if (!prefixcmp(arg, "--disable=")) { enable_service(arg + 10, 0); continue; } if (!prefixcmp(arg, "--allow-override=")) { make_service_overridable(arg + 17, 1); continue; } if (!prefixcmp(arg, "--forbid-override=")) { make_service_overridable(arg + 18, 0); continue; } if (!strcmp(arg, "--")) { ok_paths = &argv[i+1]; break; } else if (arg[0] != '-') { ok_paths = &argv[i]; break; } usage(daemon_usage); } if (log_syslog) { openlog("git-daemon", LOG_PID, LOG_DAEMON); set_die_routine(daemon_die); } else /* avoid splitting a message in the middle */ setvbuf(stderr, NULL, _IOLBF, 0); if (inetd_mode && (group_name || user_name)) die("--user and --group are incompatible with --inetd"); if (inetd_mode && (listen_port || (listen_addr.nr > 0))) die("--listen= and --port= are incompatible with --inetd"); else if (listen_port == 0) listen_port = DEFAULT_GIT_PORT; if (group_name && !user_name) die("--group supplied without --user"); if (user_name) { pass = getpwnam(user_name); if (!pass) die("user not found - %s", user_name); if (!group_name) gid = pass->pw_gid; else { group = getgrnam(group_name); if (!group) die("group not found - %s", group_name); gid = group->gr_gid; } } if (strict_paths && (!ok_paths || !*ok_paths)) die("option --strict-paths requires a whitelist"); if (base_path && !is_directory(base_path)) die("base-path '%s' does not exist or is not a directory", base_path); if (inetd_mode) { struct sockaddr_storage ss; struct sockaddr *peer = (struct sockaddr *)&ss; socklen_t slen = sizeof(ss); if (!freopen("/dev/null", "w", stderr)) die_errno("failed to redirect stderr to /dev/null"); if (getpeername(0, peer, &slen)) peer = NULL; return execute(peer); } if (detach) { daemonize(); loginfo("Ready to rumble"); } else sanitize_stdfds(); if (pid_file) store_pid(pid_file); return serve(&listen_addr, listen_port, pass, gid); }