#define HOST_NAME_MAX 256
#endif
+#ifndef NI_MAXSERV
+#define NI_MAXSERV 32
+#endif
+
static int log_syslog;
static int verbose;
static int reuseaddr;
static const char daemon_usage[] =
"git-daemon [--verbose] [--syslog] [--export-all]\n"
" [--timeout=n] [--init-timeout=n] [--strict-paths]\n"
-" [--base-path=path] [--user-path | --user-path=path]\n"
+" [--base-path=path] [--base-path-relaxed]\n"
+" [--user-path | --user-path=path]\n"
" [--interpolated-path=path]\n"
" [--reuseaddr] [--detach] [--pid-file=file]\n"
" [--[enable|disable|allow-override|forbid-override]=service]\n"
/* Take all paths relative to this one if non-NULL */
static char *base_path;
static char *interpolated_path;
+static int base_path_relaxed;
/* Flag indicating client sent extra args. */
static int saw_extended_args;
{
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.
{
static char rpath[PATH_MAX];
static char interp_path[PATH_MAX];
+ int retried_path = 0;
char *path;
char *dir;
dir = rpath;
}
- path = enter_repo(dir, strict_paths);
+ do {
+ path = enter_repo(dir, strict_paths);
+ if (path)
+ break;
+
+ /*
+ * if we fail and base_path_relaxed is enabled, try without
+ * prefixing the base path
+ */
+ if (base_path && base_path_relaxed && !retried_path) {
+ dir = itable[INTERP_SLOT_DIR].value;
+ retried_path = 1;
+ continue;
+ }
+ break;
+ } while (1);
if (!path) {
logerror("'%s': unable to chdir or not a git archive", dir);
int pathlen = strlen(path);
/* The validation is done on the paths after enter_repo
- * appends optional {.git,.git/.git} and friends, but
+ * appends optional {.git,.git/.git} and friends, but
* it does not use getcwd(). So if your /pub is
* a symlink to /mnt/pub, you can whitelist /pub and
* do not have to say /mnt/pub.
{ "receive-pack", "receivepack", receive_pack, 0, 1 },
};
-static void enable_service(const char *name, int ena) {
+static void enable_service(const char *name, int ena)
+{
int i;
for (i = 0; i < ARRAY_SIZE(daemon_service); i++) {
if (!strcmp(daemon_service[i].name, name)) {
die("No such service %s", name);
}
-static void make_service_overridable(const char *name, int ena) {
+static void make_service_overridable(const char *name, int ena)
+{
int i;
for (i = 0; i < ARRAY_SIZE(daemon_service); i++) {
if (!strcmp(daemon_service[i].name, name)) {
}
}
-void fill_in_extra_table_entries(struct interp *itable)
+static void fill_in_extra_table_entries(struct interp *itable)
{
char *hp;
if (addr->sa_family == AF_INET) {
struct sockaddr_in *sin_addr = (void *) addr;
inet_ntop(addr->sa_family, &sin_addr->sin_addr, addrbuf, sizeof(addrbuf));
- port = sin_addr->sin_port;
+ port = ntohs(sin_addr->sin_port);
#ifndef NO_IPV6
} else if (addr && addr->sa_family == AF_INET6) {
struct sockaddr_in6 *sin6_addr = (void *) addr;
inet_ntop(AF_INET6, &sin6_addr->sin6_addr, buf, sizeof(addrbuf) - 1);
strcat(buf, "]");
- port = sin6_addr->sin6_port;
+ port = ntohs(sin6_addr->sin6_port);
#endif
}
loginfo("Connection from %s:%d", addrbuf, port);
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;
usage(daemon_usage);
}
+ if (log_syslog) {
+ openlog("git-daemon", 0, LOG_DAEMON);
+ set_die_routine(daemon_die);
+ }
+
if (inetd_mode && (group_name || user_name))
die("--user and --group are incompatible with --inetd");
}
}
- if (log_syslog) {
- openlog("git-daemon", 0, LOG_DAEMON);
- set_die_routine(daemon_die);
- }
-
if (strict_paths && (!ok_paths || !*ok_paths))
die("option --strict-paths requires a whitelist");
+ if (base_path) {
+ struct stat st;
+
+ if (stat(base_path, &st) || !S_ISDIR(st.st_mode))
+ 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;