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:
@ -10,7 +10,8 @@ SYNOPSIS
|
|||||||
[verse]
|
[verse]
|
||||||
'git-daemon' [--verbose] [--syslog] [--inetd | --port=n] [--export-all]
|
'git-daemon' [--verbose] [--syslog] [--inetd | --port=n] [--export-all]
|
||||||
[--timeout=n] [--init-timeout=n] [--strict-paths]
|
[--timeout=n] [--init-timeout=n] [--strict-paths]
|
||||||
[--base-path=path] [directory...]
|
[--base-path=path] [--user-path | --user-path=path]
|
||||||
|
[directory...]
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
@ -42,8 +43,7 @@ OPTIONS
|
|||||||
This is sort of "GIT root" - if you run git-daemon with
|
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
|
'--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
|
'git://example.com/hello.git', `git-daemon` will interpret the path
|
||||||
as '/srv/git/hello.git'. Home directories (the '~login' notation)
|
as '/srv/git/hello.git'.
|
||||||
access is disabled.
|
|
||||||
|
|
||||||
--export-all::
|
--export-all::
|
||||||
Allow pulling from all directories that look like GIT repositories
|
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
|
Log to syslog instead of stderr. Note that this option does not imply
|
||||||
--verbose, thus by default only error conditions will be logged.
|
--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::
|
--verbose::
|
||||||
Log details about the incoming connections and requested files.
|
Log details about the incoming connections and requested files.
|
||||||
|
|
||||||
|
72
daemon.c
72
daemon.c
@ -13,11 +13,13 @@
|
|||||||
|
|
||||||
static int log_syslog;
|
static int log_syslog;
|
||||||
static int verbose;
|
static int verbose;
|
||||||
|
static int reuseaddr;
|
||||||
|
|
||||||
static const char daemon_usage[] =
|
static const char daemon_usage[] =
|
||||||
"git-daemon [--verbose] [--syslog] [--inetd | --port=n] [--export-all]\n"
|
"git-daemon [--verbose] [--syslog] [--inetd | --port=n] [--export-all]\n"
|
||||||
" [--timeout=n] [--init-timeout=n] [--strict-paths]\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 */
|
/* List of acceptable pathname prefixes */
|
||||||
static char **ok_paths = NULL;
|
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 */
|
/* Take all paths relative to this one if non-NULL */
|
||||||
static char *base_path = 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 */
|
/* Timeout, and initial timeout */
|
||||||
static unsigned int timeout = 0;
|
static unsigned int timeout = 0;
|
||||||
static unsigned int init_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 *path_ok(char *dir)
|
||||||
{
|
{
|
||||||
|
static char rpath[PATH_MAX];
|
||||||
char *path;
|
char *path;
|
||||||
|
|
||||||
if (avoid_alias(dir)) {
|
if (avoid_alias(dir)) {
|
||||||
@ -143,16 +152,39 @@ static char *path_ok(char *dir)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (base_path) {
|
if (*dir == '~') {
|
||||||
static char rpath[PATH_MAX];
|
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 != '/') {
|
if (*dir != '/') {
|
||||||
/* Forbid possible base-path evasion using ~paths. */
|
/* Allow only absolute */
|
||||||
logerror("'%s': Non-absolute path denied (base-path active)", dir);
|
logerror("'%s': Non-absolute path denied (base-path active)", dir);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
snprintf(rpath, PATH_MAX, "%s%s", base_path, dir);
|
snprintf(rpath, PATH_MAX, "%s%s", base_path, dir);
|
||||||
dir = rpath;
|
dir = rpath;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
path = enter_repo(dir, strict_paths);
|
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
|
#ifndef NO_IPV6
|
||||||
|
|
||||||
static int socksetup(int port, int **socklist_p)
|
static int socksetup(int port, int **socklist_p)
|
||||||
@ -491,6 +533,11 @@ static int socksetup(int port, int **socklist_p)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (set_reuse_addr(sockfd)) {
|
||||||
|
close(sockfd);
|
||||||
|
return 0; /* not fatal */
|
||||||
|
}
|
||||||
|
|
||||||
if (bind(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) {
|
if (bind(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) {
|
||||||
close(sockfd);
|
close(sockfd);
|
||||||
continue; /* not fatal */
|
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_addr.s_addr = htonl(INADDR_ANY);
|
||||||
sin.sin_port = htons(port);
|
sin.sin_port = htons(port);
|
||||||
|
|
||||||
|
if (set_reuse_addr(sockfd)) {
|
||||||
|
close(sockfd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if ( bind(sockfd, (struct sockaddr *)&sin, sizeof sin) < 0 ) {
|
if ( bind(sockfd, (struct sockaddr *)&sin, sizeof sin) < 0 ) {
|
||||||
close(sockfd);
|
close(sockfd);
|
||||||
return 0;
|
return 0;
|
||||||
@ -659,6 +711,18 @@ int main(int argc, char **argv)
|
|||||||
base_path = arg+12;
|
base_path = arg+12;
|
||||||
continue;
|
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, "--")) {
|
if (!strcmp(arg, "--")) {
|
||||||
ok_paths = &argv[i+1];
|
ok_paths = &argv[i+1];
|
||||||
break;
|
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) {
|
while (active_requests < max_requests && obj_req != NULL) {
|
||||||
if (obj_req->state == WAITING) {
|
if (obj_req->state == WAITING) {
|
||||||
if (has_sha1_file(obj_req->sha1))
|
if (has_sha1_file(obj_req->sha1))
|
||||||
release_object_request(obj_req);
|
obj_req->state = COMPLETE;
|
||||||
else
|
else
|
||||||
start_object_request(obj_req);
|
start_object_request(obj_req);
|
||||||
curl_multi_perform(curlm, &num_transfers);
|
curl_multi_perform(curlm, &num_transfers);
|
||||||
@ -468,13 +468,11 @@ static void process_alternates_response(void *callback_data)
|
|||||||
alt_req->url);
|
alt_req->url);
|
||||||
active_requests++;
|
active_requests++;
|
||||||
slot->in_use = 1;
|
slot->in_use = 1;
|
||||||
if (start_active_slot(slot)) {
|
if (!start_active_slot(slot)) {
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
got_alternates = -1;
|
got_alternates = -1;
|
||||||
slot->in_use = 0;
|
slot->in_use = 0;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} else if (slot->curl_result != CURLE_OK) {
|
} else if (slot->curl_result != CURLE_OK) {
|
||||||
if (slot->http_code != 404 &&
|
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)) {
|
} else if (memcmp(obj_req->sha1, obj_req->real_sha1, 20)) {
|
||||||
ret = error("File %s has bad hash\n", hex);
|
ret = error("File %s has bad hash\n", hex);
|
||||||
} else if (obj_req->rename < 0) {
|
} else if (obj_req->rename < 0) {
|
||||||
ret = error("unable to write sha1 filename %s: %s",
|
ret = error("unable to write sha1 filename %s",
|
||||||
obj_req->filename,
|
obj_req->filename);
|
||||||
strerror(obj_req->rename));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
release_object_request(obj_req);
|
release_object_request(obj_req);
|
||||||
|
Reference in New Issue
Block a user