Merge branches 'jc/daemon' and 'mw/http'
* jc/daemon: daemon: extend user-relative path notation. daemon: Set SO_REUSEADDR on listening sockets. daemon: do not forbid user relative paths unconditionally under --base-path * mw/http: http-fetch: Tidy control flow in process_alternate_response http: Turn on verbose Curl messages if GIT_CURL_VERBOSE set in environment http-fetch: Fix message reporting rename of object file. http-fetch: Fix object list corruption in fill_active_slots().
This commit is contained in:
commit
a8c44537fe
@ -10,7 +10,8 @@ SYNOPSIS
|
||||
[verse]
|
||||
'git-daemon' [--verbose] [--syslog] [--inetd | --port=n] [--export-all]
|
||||
[--timeout=n] [--init-timeout=n] [--strict-paths]
|
||||
[--base-path=path] [directory...]
|
||||
[--base-path=path] [--user-path | --user-path=path]
|
||||
[directory...]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@ -42,8 +43,7 @@ OPTIONS
|
||||
This is sort of "GIT root" - if you run git-daemon with
|
||||
'--base-path=/srv/git' on example.com, then if you later try to pull
|
||||
'git://example.com/hello.git', `git-daemon` will interpret the path
|
||||
as '/srv/git/hello.git'. Home directories (the '~login' notation)
|
||||
access is disabled.
|
||||
as '/srv/git/hello.git'.
|
||||
|
||||
--export-all::
|
||||
Allow pulling from all directories that look like GIT repositories
|
||||
@ -70,6 +70,15 @@ OPTIONS
|
||||
Log to syslog instead of stderr. Note that this option does not imply
|
||||
--verbose, thus by default only error conditions will be logged.
|
||||
|
||||
--user-path, --user-path=path::
|
||||
Allow ~user notation to be used in requests. When
|
||||
specified with no parameter, requests to
|
||||
git://host/~alice/foo is taken as a request to access
|
||||
'foo' repository in the home directory of user `alice`.
|
||||
If `--user-path=path` is specified, the same request is
|
||||
taken as a request to access `path/foo` repository in
|
||||
the home directory of user `alice`.
|
||||
|
||||
--verbose::
|
||||
Log details about the incoming connections and requested files.
|
||||
|
||||
|
76
daemon.c
76
daemon.c
@ -13,11 +13,13 @@
|
||||
|
||||
static int log_syslog;
|
||||
static int verbose;
|
||||
static int reuseaddr;
|
||||
|
||||
static const char daemon_usage[] =
|
||||
"git-daemon [--verbose] [--syslog] [--inetd | --port=n] [--export-all]\n"
|
||||
" [--timeout=n] [--init-timeout=n] [--strict-paths]\n"
|
||||
" [--base-path=path] [directory...]";
|
||||
" [--base-path=path] [--user-path | --user-path=path]\n"
|
||||
" [--reuseaddr] [directory...]";
|
||||
|
||||
/* List of acceptable pathname prefixes */
|
||||
static char **ok_paths = NULL;
|
||||
@ -29,6 +31,12 @@ static int export_all_trees = 0;
|
||||
/* Take all paths relative to this one if non-NULL */
|
||||
static char *base_path = NULL;
|
||||
|
||||
/* If defined, ~user notation is allowed and the string is inserted
|
||||
* after ~user/. E.g. a request to git://host/~alice/frotz would
|
||||
* go to /home/alice/pub_git/frotz with --user-path=pub_git.
|
||||
*/
|
||||
static char *user_path = NULL;
|
||||
|
||||
/* Timeout, and initial timeout */
|
||||
static unsigned int timeout = 0;
|
||||
static unsigned int init_timeout = 0;
|
||||
@ -136,6 +144,7 @@ static int avoid_alias(char *p)
|
||||
|
||||
static char *path_ok(char *dir)
|
||||
{
|
||||
static char rpath[PATH_MAX];
|
||||
char *path;
|
||||
|
||||
if (avoid_alias(dir)) {
|
||||
@ -143,15 +152,38 @@ static char *path_ok(char *dir)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (base_path) {
|
||||
static char rpath[PATH_MAX];
|
||||
if (*dir == '~') {
|
||||
if (!user_path) {
|
||||
logerror("'%s': User-path not allowed", dir);
|
||||
return NULL;
|
||||
}
|
||||
if (*user_path) {
|
||||
/* Got either "~alice" or "~alice/foo";
|
||||
* rewrite them to "~alice/%s" or
|
||||
* "~alice/%s/foo".
|
||||
*/
|
||||
int namlen, restlen = strlen(dir);
|
||||
char *slash = strchr(dir, '/');
|
||||
if (!slash)
|
||||
slash = dir + restlen;
|
||||
namlen = slash - dir;
|
||||
restlen -= namlen;
|
||||
loginfo("userpath <%s>, request <%s>, namlen %d, restlen %d, slash <%s>", user_path, dir, namlen, restlen, slash);
|
||||
snprintf(rpath, PATH_MAX, "%.*s/%s%.*s",
|
||||
namlen, dir, user_path, restlen, slash);
|
||||
dir = rpath;
|
||||
}
|
||||
}
|
||||
else if (base_path) {
|
||||
if (*dir != '/') {
|
||||
/* Forbid possible base-path evasion using ~paths. */
|
||||
/* Allow only absolute */
|
||||
logerror("'%s': Non-absolute path denied (base-path active)", dir);
|
||||
return NULL;
|
||||
}
|
||||
snprintf(rpath, PATH_MAX, "%s%s", base_path, dir);
|
||||
dir = rpath;
|
||||
else {
|
||||
snprintf(rpath, PATH_MAX, "%s%s", base_path, dir);
|
||||
dir = rpath;
|
||||
}
|
||||
}
|
||||
|
||||
path = enter_repo(dir, strict_paths);
|
||||
@ -447,6 +479,16 @@ static void child_handler(int signo)
|
||||
}
|
||||
}
|
||||
|
||||
static int set_reuse_addr(int sockfd)
|
||||
{
|
||||
int on = 1;
|
||||
|
||||
if (!reuseaddr)
|
||||
return 0;
|
||||
return setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
|
||||
&on, sizeof(on));
|
||||
}
|
||||
|
||||
#ifndef NO_IPV6
|
||||
|
||||
static int socksetup(int port, int **socklist_p)
|
||||
@ -491,6 +533,11 @@ static int socksetup(int port, int **socklist_p)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (set_reuse_addr(sockfd)) {
|
||||
close(sockfd);
|
||||
return 0; /* not fatal */
|
||||
}
|
||||
|
||||
if (bind(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) {
|
||||
close(sockfd);
|
||||
continue; /* not fatal */
|
||||
@ -533,6 +580,11 @@ static int socksetup(int port, int **socklist_p)
|
||||
sin.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
sin.sin_port = htons(port);
|
||||
|
||||
if (set_reuse_addr(sockfd)) {
|
||||
close(sockfd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( bind(sockfd, (struct sockaddr *)&sin, sizeof sin) < 0 ) {
|
||||
close(sockfd);
|
||||
return 0;
|
||||
@ -659,6 +711,18 @@ int main(int argc, char **argv)
|
||||
base_path = arg+12;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--reuseaddr")) {
|
||||
reuseaddr = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--user-path")) {
|
||||
user_path = "";
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(arg, "--user-path=", 12)) {
|
||||
user_path = arg + 12;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--")) {
|
||||
ok_paths = &argv[i+1];
|
||||
break;
|
||||
|
13
http-fetch.c
13
http-fetch.c
@ -311,7 +311,7 @@ void fill_active_slots(void)
|
||||
while (active_requests < max_requests && obj_req != NULL) {
|
||||
if (obj_req->state == WAITING) {
|
||||
if (has_sha1_file(obj_req->sha1))
|
||||
release_object_request(obj_req);
|
||||
obj_req->state = COMPLETE;
|
||||
else
|
||||
start_object_request(obj_req);
|
||||
curl_multi_perform(curlm, &num_transfers);
|
||||
@ -468,13 +468,11 @@ static void process_alternates_response(void *callback_data)
|
||||
alt_req->url);
|
||||
active_requests++;
|
||||
slot->in_use = 1;
|
||||
if (start_active_slot(slot)) {
|
||||
return;
|
||||
} else {
|
||||
if (!start_active_slot(slot)) {
|
||||
got_alternates = -1;
|
||||
slot->in_use = 0;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
} else if (slot->curl_result != CURLE_OK) {
|
||||
if (slot->http_code != 404 &&
|
||||
@ -822,9 +820,8 @@ static int fetch_object(struct alt_base *repo, unsigned char *sha1)
|
||||
} else if (memcmp(obj_req->sha1, obj_req->real_sha1, 20)) {
|
||||
ret = error("File %s has bad hash\n", hex);
|
||||
} else if (obj_req->rename < 0) {
|
||||
ret = error("unable to write sha1 filename %s: %s",
|
||||
obj_req->filename,
|
||||
strerror(obj_req->rename));
|
||||
ret = error("unable to write sha1 filename %s",
|
||||
obj_req->filename);
|
||||
}
|
||||
|
||||
release_object_request(obj_req);
|
||||
|
Loading…
Reference in New Issue
Block a user