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:
Junio C Hamano
2006-02-05 23:54:14 -08:00
4 changed files with 90 additions and 17 deletions

View File

@ -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.

View File

@ -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;

View File

@ -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);

3
http.c
View File

@ -192,6 +192,9 @@ static CURL* get_curl_handle(void)
curl_easy_setopt(result, CURLOPT_FOLLOWLOCATION, 1); curl_easy_setopt(result, CURLOPT_FOLLOWLOCATION, 1);
if (getenv("GIT_CURL_VERBOSE"))
curl_easy_setopt(result, CURLOPT_VERBOSE, 1);
return result; return result;
} }