From dd4676299dde0a4c6f8a471e6353170f86a78c8a Mon Sep 17 00:00:00 2001 From: Jon Loeliger Date: Tue, 26 Sep 2006 09:47:43 -0500 Subject: Cleaned up git-daemon virtual hosting support. Standardized on lowercase hostnames from client. Added interpolation values for the IP address, port and canonical hostname of the server as it is contacted and named by the client and passed in via the extended args. Added --listen=host_or_ipaddr option suport. Renamed port variable as "listen_port" correspondingly as well. Documented mutual exclusivity of --inetd option with --user, --group, --listen and --port options. Added compat/inet_pton.c from Paul Vixie as needed. Small memory leaks need to be cleaned up still. Signed-off-by: Jon Loeliger Signed-off-by: Junio C Hamano --- daemon.c | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 129 insertions(+), 22 deletions(-) (limited to 'daemon.c') diff --git a/daemon.c b/daemon.c index eb4f3f1e9f..69ea35c22d 100644 --- a/daemon.c +++ b/daemon.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "pkt-line.h" #include "cache.h" #include "exec_cmd.h" @@ -19,13 +20,15 @@ static int verbose; static int reuseaddr; static const char daemon_usage[] = -"git-daemon [--verbose] [--syslog] [--inetd | --port=n] [--export-all]\n" +"git-daemon [--verbose] [--syslog] [--export-all]\n" " [--timeout=n] [--init-timeout=n] [--strict-paths]\n" " [--base-path=path] [--user-path | --user-path=path]\n" " [--interpolated-path=path]\n" " [--reuseaddr] [--detach] [--pid-file=file]\n" " [--[enable|disable|allow-override|forbid-override]=service]\n" -" [--user=user [[--group=group]] [directory...]"; +" [--inetd | [--listen=host_or_ipaddr] [--port=n]\n" +" [--user=user [--group=group]]\n" +" [directory...]"; /* List of acceptable pathname prefixes */ static char **ok_paths; @@ -56,11 +59,17 @@ static unsigned int init_timeout; * Feel free to make dynamic as needed. */ #define INTERP_SLOT_HOST (0) -#define INTERP_SLOT_DIR (1) -#define INTERP_SLOT_PERCENT (2) +#define INTERP_SLOT_CANON_HOST (1) +#define INTERP_SLOT_IP (2) +#define INTERP_SLOT_PORT (3) +#define INTERP_SLOT_DIR (4) +#define INTERP_SLOT_PERCENT (5) static struct interp interp_table[] = { { "%H", 0}, + { "%CH", 0}, + { "%IP", 0}, + { "%P", 0}, { "%D", 0}, { "%%", "%"}, }; @@ -408,9 +417,17 @@ static void parse_extra_args(char *extra_args, int buflen) val = extra_args + 5; vallen = strlen(val) + 1; if (*val) { - char *save = xmalloc(vallen); + char *port; + char *save = xmalloc(vallen); /* FIXME: Leak */ + interp_table[INTERP_SLOT_HOST].value = save; strlcpy(save, val, vallen); + port = strrchr(save, ':'); + if (port) { + *port = 0; + port++; + interp_table[INTERP_SLOT_PORT].value = port; + } } /* On to the next one */ extra_args = val + vallen; @@ -418,6 +435,73 @@ static void parse_extra_args(char *extra_args, int buflen) } } +void fill_in_extra_table_entries(struct interp *itable) +{ + char *hp; + char *canon_host = NULL; + char *ipaddr = NULL; + + /* + * Replace literal host with lowercase-ized hostname. + */ + hp = interp_table[INTERP_SLOT_HOST].value; + for ( ; *hp; hp++) + *hp = tolower(*hp); + + /* + * Locate canonical hostname and its IP address. + */ +#ifndef NO_IPV6 + { + struct addrinfo hints; + struct addrinfo *ai, *ai0; + int gai; + static char addrbuf[HOST_NAME_MAX + 1]; + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_CANONNAME; + + gai = getaddrinfo(interp_table[INTERP_SLOT_HOST].value, 0, &hints, &ai0); + if (!gai) { + for (ai = ai0; ai; ai = ai->ai_next) { + struct sockaddr_in *sin_addr = (void *)ai->ai_addr; + + canon_host = xstrdup(ai->ai_canonname); + inet_ntop(AF_INET, &sin_addr->sin_addr, + addrbuf, sizeof(addrbuf)); + ipaddr = addrbuf; + break; + } + freeaddrinfo(ai0); + } + } +#else + { + struct hostent *hent; + struct sockaddr_in sa; + char **ap; + static char addrbuf[HOST_NAME_MAX + 1]; + + hent = gethostbyname(interp_table[INTERP_SLOT_HOST].value); + canon_host = xstrdup(hent->h_name); + + 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)); + ipaddr = addrbuf; + } +#endif + + interp_table[INTERP_SLOT_CANON_HOST].value = canon_host; /* FIXME: Leak */ + interp_table[INTERP_SLOT_IP].value = xstrdup(ipaddr); /* FIXME: Leak */ +} + + static int execute(struct sockaddr *addr) { static char line[1000]; @@ -458,8 +542,10 @@ static int execute(struct sockaddr *addr) if (len && line[len-1] == '\n') line[--len] = 0; - if (len != pktlen) + if (len != pktlen) { parse_extra_args(line + len + 1, pktlen - len - 1); + fill_in_extra_table_entries(interp_table); + } for (i = 0; i < ARRAY_SIZE(daemon_service); i++) { struct daemon_service *s = &(daemon_service[i]); @@ -663,23 +749,22 @@ static int set_reuse_addr(int sockfd) #ifndef NO_IPV6 -static int socksetup(int port, int **socklist_p) +static int socksetup(char *listen_addr, int listen_port, int **socklist_p) { int socknum = 0, *socklist = NULL; int maxfd = -1; char pbuf[NI_MAXSERV]; - struct addrinfo hints, *ai0, *ai; int gai; - sprintf(pbuf, "%d", port); + sprintf(pbuf, "%d", listen_port); memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; hints.ai_flags = AI_PASSIVE; - gai = getaddrinfo(NULL, pbuf, &hints, &ai0); + gai = getaddrinfo(listen_addr, pbuf, &hints, &ai0); if (gai) die("getaddrinfo() failed: %s\n", gai_strerror(gai)); @@ -733,20 +818,27 @@ static int socksetup(int port, int **socklist_p) #else /* NO_IPV6 */ -static int socksetup(int port, int **socklist_p) +static int socksetup(char *lisen_addr, int listen_port, int **socklist_p) { struct sockaddr_in sin; int sockfd; + memset(&sin, 0, sizeof sin); + sin.sin_family = AF_INET; + sin.sin_port = htons(listen_port); + + if (listen_addr) { + /* Well, host better be an IP address here. */ + if (inet_pton(AF_INET, listen_addr, &sin.sin_addr.s_addr) <= 0) + return 0; + } else { + sin.sin_addr.s_addr = htonl(INADDR_ANY); + } + sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) return 0; - memset(&sin, 0, sizeof sin); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = htonl(INADDR_ANY); - sin.sin_port = htons(port); - if (set_reuse_addr(sockfd)) { close(sockfd); return 0; @@ -855,13 +947,14 @@ static void store_pid(const char *path) fclose(f); } -static int serve(int port, struct passwd *pass, gid_t gid) +static int serve(char *listen_addr, int listen_port, struct passwd *pass, gid_t gid) { int socknum, *socklist; - socknum = socksetup(port, &socklist); + socknum = socksetup(listen_addr, listen_port, &socklist); if (socknum == 0) - die("unable to allocate any listen sockets on port %u", port); + die("unable to allocate any listen sockets on host %s port %u", + listen_addr, listen_port); if (pass && gid && (initgroups(pass->pw_name, gid) || setgid (gid) || @@ -873,7 +966,8 @@ static int serve(int port, struct passwd *pass, gid_t gid) int main(int argc, char **argv) { - int port = DEFAULT_GIT_PORT; + int listen_port = 0; + char *listen_addr = NULL; int inetd_mode = 0; const char *pid_file = NULL, *user_name = NULL, *group_name = NULL; int detach = 0; @@ -890,12 +984,20 @@ int main(int argc, char **argv) for (i = 1; i < argc; i++) { char *arg = argv[i]; + if (!strncmp(arg, "--listen=", 9)) { + char *p = arg + 9; + char *ph = listen_addr = xmalloc(strlen(arg + 9) + 1); + while (*p) + *ph++ = tolower(*p++); + *ph = 0; + continue; + } if (!strncmp(arg, "--port=", 7)) { char *end; unsigned long n; n = strtoul(arg+7, &end, 0); if (arg[7] && !*end) { - port = n; + listen_port = n; continue; } } @@ -995,6 +1097,11 @@ int main(int argc, char **argv) if (inetd_mode && (group_name || user_name)) die("--user and --group are incompatible with --inetd"); + if (inetd_mode && (listen_port || listen_addr)) + 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"); @@ -1043,5 +1150,5 @@ int main(int argc, char **argv) if (pid_file) store_pid(pid_file); - return serve(port, pass, gid); + return serve(listen_addr, listen_port, pass, gid); } -- cgit v1.3 From eb30aed7c69190fd648947d54bbb9ebe53c67715 Mon Sep 17 00:00:00 2001 From: Jon Loeliger Date: Wed, 27 Sep 2006 11:16:10 -0500 Subject: Removed memory leaks from interpolation table uses. Clarified that parse_extra_args()s results in interpolation table entries. Removed a few trailing whitespace occurrences. Signed-off-by: Jon Loeliger Signed-off-by: Junio C Hamano --- daemon.c | 52 ++++++++++++++++++++++++++++++++-------------------- interpolate.c | 26 ++++++++++++++++++++++++++ interpolate.h | 3 +++ 3 files changed, 61 insertions(+), 20 deletions(-) (limited to 'daemon.c') diff --git a/daemon.c b/daemon.c index 69ea35c22d..5335d212c3 100644 --- a/daemon.c +++ b/daemon.c @@ -71,7 +71,7 @@ static struct interp interp_table[] = { { "%IP", 0}, { "%P", 0}, { "%D", 0}, - { "%%", "%"}, + { "%%", 0}, }; @@ -405,7 +405,11 @@ static void make_service_overridable(const char *name, int ena) { die("No such service %s", name); } -static void parse_extra_args(char *extra_args, int buflen) +/* + * Separate the "extra args" information as supplied by the client connection. + * Any resulting data is squirrelled away in the given interpolation table. + */ +static void parse_extra_args(struct interp *table, char *extra_args, int buflen) { char *val; int vallen; @@ -417,18 +421,17 @@ static void parse_extra_args(char *extra_args, int buflen) val = extra_args + 5; vallen = strlen(val) + 1; if (*val) { - char *port; - char *save = xmalloc(vallen); /* FIXME: Leak */ - - interp_table[INTERP_SLOT_HOST].value = save; - strlcpy(save, val, vallen); - port = strrchr(save, ':'); + /* Split : at colon. */ + char *host = val; + char *port = strrchr(host, ':'); if (port) { *port = 0; port++; - interp_table[INTERP_SLOT_PORT].value = port; + interp_set_entry(table, INTERP_SLOT_PORT, port); } + interp_set_entry(table, INTERP_SLOT_HOST, host); } + /* On to the next one */ extra_args = val + vallen; } @@ -438,8 +441,6 @@ static void parse_extra_args(char *extra_args, int buflen) void fill_in_extra_table_entries(struct interp *itable) { char *hp; - char *canon_host = NULL; - char *ipaddr = NULL; /* * Replace literal host with lowercase-ized hostname. @@ -466,10 +467,12 @@ void fill_in_extra_table_entries(struct interp *itable) for (ai = ai0; ai; ai = ai->ai_next) { struct sockaddr_in *sin_addr = (void *)ai->ai_addr; - canon_host = xstrdup(ai->ai_canonname); inet_ntop(AF_INET, &sin_addr->sin_addr, addrbuf, sizeof(addrbuf)); - ipaddr = addrbuf; + interp_set_entry(interp_table, + INTERP_SLOT_CANON_HOST, ai->ai_canonname); + interp_set_entry(interp_table, + INTERP_SLOT_IP, addrbuf); break; } freeaddrinfo(ai0); @@ -483,7 +486,6 @@ void fill_in_extra_table_entries(struct interp *itable) static char addrbuf[HOST_NAME_MAX + 1]; hent = gethostbyname(interp_table[INTERP_SLOT_HOST].value); - canon_host = xstrdup(hent->h_name); ap = hent->h_addr_list; memset(&sa, 0, sizeof sa); @@ -493,12 +495,11 @@ void fill_in_extra_table_entries(struct interp *itable) inet_ntop(hent->h_addrtype, &sa.sin_addr, addrbuf, sizeof(addrbuf)); - ipaddr = addrbuf; + + interp_set_entry(interp_table, INTERP_SLOT_CANON_HOST, hent->h_name); + interp_set_entry(interp_table, INTERP_SLOT_IP, addrbuf); } #endif - - interp_table[INTERP_SLOT_CANON_HOST].value = canon_host; /* FIXME: Leak */ - interp_table[INTERP_SLOT_IP].value = xstrdup(ipaddr); /* FIXME: Leak */ } @@ -542,8 +543,14 @@ static int execute(struct sockaddr *addr) if (len && line[len-1] == '\n') line[--len] = 0; + /* + * Initialize the path interpolation table for this connection. + */ + interp_clear_table(interp_table, ARRAY_SIZE(interp_table)); + interp_set_entry(interp_table, INTERP_SLOT_PERCENT, "%"); + if (len != pktlen) { - parse_extra_args(line + len + 1, pktlen - len - 1); + parse_extra_args(interp_table, line + len + 1, pktlen - len - 1); fill_in_extra_table_entries(interp_table); } @@ -553,7 +560,12 @@ static int execute(struct sockaddr *addr) if (!strncmp("git-", line, 4) && !strncmp(s->name, line + 4, namelen) && line[namelen + 4] == ' ') { - interp_table[INTERP_SLOT_DIR].value = line+namelen+5; + /* + * Note: The directory here is probably context sensitive, + * and might depend on the actual service being performed. + */ + interp_set_entry(interp_table, + INTERP_SLOT_DIR, line + namelen + 5); return run_service(interp_table, s); } } diff --git a/interpolate.c b/interpolate.c index 4570c123dc..62701d8435 100644 --- a/interpolate.c +++ b/interpolate.c @@ -4,9 +4,35 @@ #include +#include "git-compat-util.h" #include "interpolate.h" +void interp_set_entry(struct interp *table, int slot, char *value) +{ + char *oldval = table[slot].value; + char *newval = value; + + if (oldval) + free(oldval); + + if (value) + newval = xstrdup(value); + + table[slot].value = newval; +} + + +void interp_clear_table(struct interp *table, int ninterps) +{ + int i; + + for (i = 0; i < ninterps; i++) { + interp_set_entry(table, i, NULL); + } +} + + /* * Convert a NUL-terminated string in buffer orig * into the supplied buffer, result, whose length is reslen, diff --git a/interpolate.h b/interpolate.h index d16f9244f3..a55fb8e071 100644 --- a/interpolate.h +++ b/interpolate.h @@ -16,6 +16,9 @@ struct interp { char *value; }; +extern void interp_set_entry(struct interp *table, int slot, char *value); +extern void interp_clear_table(struct interp *table, int ninterps); + extern int interpolate(char *result, int reslen, const char *orig, const struct interp *interps, int ninterps); -- cgit v1.3