revised^2: git-daemon extra paranoia, and path DWIM
[git.git] / daemon.c
1 #include "cache.h"
2 #include "pkt-line.h"
3 #include <signal.h>
4 #include <sys/wait.h>
5 #include <sys/socket.h>
6 #include <sys/time.h>
7 #include <netdb.h>
8 #include <netinet/in.h>
9 #include <arpa/inet.h>
10 #include <syslog.h>
11
12 static int log_syslog;
13 static int verbose;
14
15 static const char daemon_usage[] = "git-daemon [--verbose] [--syslog] [--inetd | --port=n] [--export-all] [directory...]";
16
17 /* List of acceptable pathname prefixes */
18 static char **ok_paths = NULL;
19
20 /* If this is set, git-daemon-export-ok is not required */
21 static int export_all_trees = 0;
22
23
24 static void logreport(int priority, const char *err, va_list params)
25 {
26         /* We should do a single write so that it is atomic and output
27          * of several processes do not get intermingled. */
28         char buf[1024];
29         int buflen;
30         int maxlen, msglen;
31
32         /* sizeof(buf) should be big enough for "[pid] \n" */
33         buflen = snprintf(buf, sizeof(buf), "[%ld] ", (long) getpid());
34
35         maxlen = sizeof(buf) - buflen - 1; /* -1 for our own LF */
36         msglen = vsnprintf(buf + buflen, maxlen, err, params);
37
38         if (log_syslog) {
39                 syslog(priority, "%s", buf);
40                 return;
41         }
42
43         /* maxlen counted our own LF but also counts space given to
44          * vsnprintf for the terminating NUL.  We want to make sure that
45          * we have space for our own LF and NUL after the "meat" of the
46          * message, so truncate it at maxlen - 1.
47          */
48         if (msglen > maxlen - 1)
49                 msglen = maxlen - 1;
50         else if (msglen < 0)
51                 msglen = 0; /* Protect against weird return values. */
52         buflen += msglen;
53
54         buf[buflen++] = '\n';
55         buf[buflen] = '\0';
56
57         write(2, buf, buflen);
58 }
59
60 static void logerror(const char *err, ...)
61 {
62         va_list params;
63         va_start(params, err);
64         logreport(LOG_ERR, err, params);
65         va_end(params);
66 }
67
68 static void loginfo(const char *err, ...)
69 {
70         va_list params;
71         if (!verbose)
72                 return;
73         va_start(params, err);
74         logreport(LOG_INFO, err, params);
75         va_end(params);
76 }
77
78 static int path_ok(const char *dir)
79 {
80         const char *p = dir;
81         char **pp;
82         int sl, ndot;
83
84         /* The pathname here should be an absolute path. */
85         if ( *p++ != '/' )
86                 return 0;
87
88         sl = 1;  ndot = 0;
89
90         for (;;) {
91                 if ( *p == '.' ) {
92                         ndot++;
93                 } else if ( *p == '\0' ) {
94                         /* Reject "." and ".." at the end of the path */
95                         if ( sl && ndot > 0 && ndot < 3 )
96                                 return 0;
97
98                         /* Otherwise OK */
99                         break;
100                 } else if ( *p == '/' ) {
101                         /* Refuse "", "." or ".." */
102                         if ( sl && ndot < 3 )
103                                 return 0;
104                         sl = 1;
105                         ndot = 0;
106                 } else {
107                         sl = ndot = 0;
108                 }
109                 p++;
110         }
111
112         if ( ok_paths && *ok_paths ) {
113                 int ok = 0;
114                 int dirlen = strlen(dir);
115
116                 for ( pp = ok_paths ; *pp ; pp++ ) {
117                         int len = strlen(*pp);
118                         if ( len <= dirlen &&
119                              !strncmp(*pp, dir, len) &&
120                              (dir[len] == '/' || dir[len] == '\0') ) {
121                                 ok = 1;
122                                 break;
123                         }
124                 }
125
126                 if ( !ok )
127                         return 0; /* Path not in whitelist */
128         }
129
130         return 1;               /* Path acceptable */
131 }
132
133 static int set_dir(const char *dir)
134 {
135         if (!path_ok(dir)) {
136                 errno = EACCES;
137                 return -1;
138         }
139
140         if ( chdir(dir) )
141                 return -1;
142         
143         /*
144          * Security on the cheap.
145          *
146          * We want a readable HEAD, usable "objects" directory, and 
147          * a "git-daemon-export-ok" flag that says that the other side
148          * is ok with us doing this.
149          */
150         if (!export_all_trees && access("git-daemon-export-ok", F_OK)) {
151                 errno = EACCES;
152                 return -1;
153         }
154
155         if (access("objects/", X_OK) || access("HEAD", R_OK)) {
156                 errno = EINVAL;
157                 return -1;
158         }
159
160         /* If all this passed, we're OK */
161         return 0;
162 }
163
164 static int upload(char *dir)
165 {
166         /* Try paths in this order */
167         static const char *paths[] = { "%s", "%s/.git", "%s.git", "%s.git/.git", NULL };
168         const char **pp;
169         /* Enough for the longest path above including final null */
170         int buflen = strlen(dir)+10;
171         char *dirbuf = xmalloc(buflen);
172
173         loginfo("Request for '%s'", dir);
174
175         for ( pp = paths ; *pp ; pp++ ) {
176                 snprintf(dirbuf, buflen, *pp, dir);
177                 if ( !set_dir(dirbuf) )
178                         break;
179         }
180
181         if ( !*pp ) {
182                 logerror("Cannot set directory '%s': %s", dir, strerror(errno));
183                 return -1;
184         }
185
186         /*
187          * We'll ignore SIGTERM from now on, we have a
188          * good client.
189          */
190         signal(SIGTERM, SIG_IGN);
191
192         /* git-upload-pack only ever reads stuff, so this is safe */
193         execlp("git-upload-pack", "git-upload-pack", ".", NULL);
194         return -1;
195 }
196
197 static int execute(void)
198 {
199         static char line[1000];
200         int len;
201
202         len = packet_read_line(0, line, sizeof(line));
203
204         if (len && line[len-1] == '\n')
205                 line[--len] = 0;
206
207         if (!strncmp("git-upload-pack /", line, 17))
208                 return upload(line+16);
209
210         logerror("Protocol error: '%s'", line);
211         return -1;
212 }
213
214
215 /*
216  * We count spawned/reaped separately, just to avoid any
217  * races when updating them from signals. The SIGCHLD handler
218  * will only update children_reaped, and the fork logic will
219  * only update children_spawned.
220  *
221  * MAX_CHILDREN should be a power-of-two to make the modulus
222  * operation cheap. It should also be at least twice
223  * the maximum number of connections we will ever allow.
224  */
225 #define MAX_CHILDREN 128
226
227 static int max_connections = 25;
228
229 /* These are updated by the signal handler */
230 static volatile unsigned int children_reaped = 0;
231 static pid_t dead_child[MAX_CHILDREN];
232
233 /* These are updated by the main loop */
234 static unsigned int children_spawned = 0;
235 static unsigned int children_deleted = 0;
236
237 static struct child {
238         pid_t pid;
239         int addrlen;
240         struct sockaddr_storage address;
241 } live_child[MAX_CHILDREN];
242
243 static void add_child(int idx, pid_t pid, struct sockaddr *addr, int addrlen)
244 {
245         live_child[idx].pid = pid;
246         live_child[idx].addrlen = addrlen;
247         memcpy(&live_child[idx].address, addr, addrlen);
248 }
249
250 /*
251  * Walk from "deleted" to "spawned", and remove child "pid".
252  *
253  * We move everything up by one, since the new "deleted" will
254  * be one higher.
255  */
256 static void remove_child(pid_t pid, unsigned deleted, unsigned spawned)
257 {
258         struct child n;
259
260         deleted %= MAX_CHILDREN;
261         spawned %= MAX_CHILDREN;
262         if (live_child[deleted].pid == pid) {
263                 live_child[deleted].pid = -1;
264                 return;
265         }
266         n = live_child[deleted];
267         for (;;) {
268                 struct child m;
269                 deleted = (deleted + 1) % MAX_CHILDREN;
270                 if (deleted == spawned)
271                         die("could not find dead child %d\n", pid);
272                 m = live_child[deleted];
273                 live_child[deleted] = n;
274                 if (m.pid == pid)
275                         return;
276                 n = m;
277         }
278 }
279
280 /*
281  * This gets called if the number of connections grows
282  * past "max_connections".
283  *
284  * We _should_ start off by searching for connections
285  * from the same IP, and if there is some address wth
286  * multiple connections, we should kill that first.
287  *
288  * As it is, we just "randomly" kill 25% of the connections,
289  * and our pseudo-random generator sucks too. I have no
290  * shame.
291  *
292  * Really, this is just a place-holder for a _real_ algorithm.
293  */
294 static void kill_some_children(int signo, unsigned start, unsigned stop)
295 {
296         start %= MAX_CHILDREN;
297         stop %= MAX_CHILDREN;
298         while (start != stop) {
299                 if (!(start & 3))
300                         kill(live_child[start].pid, signo);
301                 start = (start + 1) % MAX_CHILDREN;
302         }
303 }
304
305 static void check_max_connections(void)
306 {
307         for (;;) {
308                 int active;
309                 unsigned spawned, reaped, deleted;
310
311                 spawned = children_spawned;
312                 reaped = children_reaped;
313                 deleted = children_deleted;
314
315                 while (deleted < reaped) {
316                         pid_t pid = dead_child[deleted % MAX_CHILDREN];
317                         remove_child(pid, deleted, spawned);
318                         deleted++;
319                 }
320                 children_deleted = deleted;
321
322                 active = spawned - deleted;
323                 if (active <= max_connections)
324                         break;
325
326                 /* Kill some unstarted connections with SIGTERM */
327                 kill_some_children(SIGTERM, deleted, spawned);
328                 if (active <= max_connections << 1)
329                         break;
330
331                 /* If the SIGTERM thing isn't helping use SIGKILL */
332                 kill_some_children(SIGKILL, deleted, spawned);
333                 sleep(1);
334         }
335 }
336
337 static void handle(int incoming, struct sockaddr *addr, int addrlen)
338 {
339         pid_t pid = fork();
340         char addrbuf[256] = "";
341         int port = -1;
342
343         if (pid) {
344                 unsigned idx;
345
346                 close(incoming);
347                 if (pid < 0)
348                         return;
349
350                 idx = children_spawned % MAX_CHILDREN;
351                 children_spawned++;
352                 add_child(idx, pid, addr, addrlen);
353
354                 check_max_connections();
355                 return;
356         }
357
358         dup2(incoming, 0);
359         dup2(incoming, 1);
360         close(incoming);
361
362         if (addr->sa_family == AF_INET) {
363                 struct sockaddr_in *sin_addr = (void *) addr;
364                 inet_ntop(AF_INET, &sin_addr->sin_addr, addrbuf, sizeof(addrbuf));
365                 port = sin_addr->sin_port;
366
367         } else if (addr->sa_family == AF_INET6) {
368                 struct sockaddr_in6 *sin6_addr = (void *) addr;
369
370                 char *buf = addrbuf;
371                 *buf++ = '['; *buf = '\0'; /* stpcpy() is cool */
372                 inet_ntop(AF_INET6, &sin6_addr->sin6_addr, buf, sizeof(addrbuf) - 1);
373                 strcat(buf, "]");
374
375                 port = sin6_addr->sin6_port;
376         }
377         loginfo("Connection from %s:%d", addrbuf, port);
378
379         exit(execute());
380 }
381
382 static void child_handler(int signo)
383 {
384         for (;;) {
385                 int status;
386                 pid_t pid = waitpid(-1, &status, WNOHANG);
387
388                 if (pid > 0) {
389                         unsigned reaped = children_reaped;
390                         dead_child[reaped % MAX_CHILDREN] = pid;
391                         children_reaped = reaped + 1;
392                         /* XXX: Custom logging, since we don't wanna getpid() */
393                         if (verbose) {
394                                 char *dead = "";
395                                 if (!WIFEXITED(status) || WEXITSTATUS(status) > 0)
396                                         dead = " (with error)";
397                                 if (log_syslog)
398                                         syslog(LOG_INFO, "[%d] Disconnected%s", pid, dead);
399                                 else
400                                         fprintf(stderr, "[%d] Disconnected%s\n", pid, dead);
401                         }
402                         continue;
403                 }
404                 break;
405         }
406 }
407
408 static int serve(int port)
409 {
410         struct addrinfo hints, *ai0, *ai;
411         int gai;
412         int socknum = 0, *socklist = NULL;
413         int maxfd = -1;
414         fd_set fds_init, fds;
415         char pbuf[NI_MAXSERV];
416
417         signal(SIGCHLD, child_handler);
418
419         sprintf(pbuf, "%d", port);
420         memset(&hints, 0, sizeof(hints));
421         hints.ai_family = AF_UNSPEC;
422         hints.ai_socktype = SOCK_STREAM;
423         hints.ai_protocol = IPPROTO_TCP;
424         hints.ai_flags = AI_PASSIVE;
425
426         gai = getaddrinfo(NULL, pbuf, &hints, &ai0);
427         if (gai)
428                 die("getaddrinfo() failed: %s\n", gai_strerror(gai));
429
430         FD_ZERO(&fds_init);
431
432         for (ai = ai0; ai; ai = ai->ai_next) {
433                 int sockfd;
434                 int *newlist;
435
436                 sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
437                 if (sockfd < 0)
438                         continue;
439                 if (sockfd >= FD_SETSIZE) {
440                         error("too large socket descriptor.");
441                         close(sockfd);
442                         continue;
443                 }
444
445 #ifdef IPV6_V6ONLY
446                 if (ai->ai_family == AF_INET6) {
447                         int on = 1;
448                         setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,
449                                    &on, sizeof(on));
450                         /* Note: error is not fatal */
451                 }
452 #endif
453
454                 if (bind(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) {
455                         close(sockfd);
456                         continue;       /* not fatal */
457                 }
458                 if (listen(sockfd, 5) < 0) {
459                         close(sockfd);
460                         continue;       /* not fatal */
461                 }
462
463                 newlist = realloc(socklist, sizeof(int) * (socknum + 1));
464                 if (!newlist)
465                         die("memory allocation failed: %s", strerror(errno));
466
467                 socklist = newlist;
468                 socklist[socknum++] = sockfd;
469
470                 FD_SET(sockfd, &fds_init);
471                 if (maxfd < sockfd)
472                         maxfd = sockfd;
473         }
474
475         freeaddrinfo(ai0);
476
477         if (socknum == 0)
478                 die("unable to allocate any listen sockets on port %u", port);
479
480         for (;;) {
481                 int i;
482                 fds = fds_init;
483                 
484                 if (select(maxfd + 1, &fds, NULL, NULL, NULL) < 0) {
485                         if (errno != EINTR) {
486                                 error("select failed, resuming: %s",
487                                       strerror(errno));
488                                 sleep(1);
489                         }
490                         continue;
491                 }
492
493                 for (i = 0; i < socknum; i++) {
494                         int sockfd = socklist[i];
495
496                         if (FD_ISSET(sockfd, &fds)) {
497                                 struct sockaddr_storage ss;
498                                 int sslen = sizeof(ss);
499                                 int incoming = accept(sockfd, (struct sockaddr *)&ss, &sslen);
500                                 if (incoming < 0) {
501                                         switch (errno) {
502                                         case EAGAIN:
503                                         case EINTR:
504                                         case ECONNABORTED:
505                                                 continue;
506                                         default:
507                                                 die("accept returned %s", strerror(errno));
508                                         }
509                                 }
510                                 handle(incoming, (struct sockaddr *)&ss, sslen);
511                         }
512                 }
513         }
514 }
515
516 int main(int argc, char **argv)
517 {
518         int port = DEFAULT_GIT_PORT;
519         int inetd_mode = 0;
520         int i;
521
522         for (i = 1; i < argc; i++) {
523                 char *arg = argv[i];
524
525                 if (!strncmp(arg, "--port=", 7)) {
526                         char *end;
527                         unsigned long n;
528                         n = strtoul(arg+7, &end, 0);
529                         if (arg[7] && !*end) {
530                                 port = n;
531                                 continue;
532                         }
533                 }
534                 if (!strcmp(arg, "--inetd")) {
535                         inetd_mode = 1;
536                         continue;
537                 }
538                 if (!strcmp(arg, "--verbose")) {
539                         verbose = 1;
540                         continue;
541                 }
542                 if (!strcmp(arg, "--syslog")) {
543                         log_syslog = 1;
544                         openlog("git-daemon", 0, LOG_DAEMON);
545                         continue;
546                 }
547                 if (!strcmp(arg, "--export-all")) {
548                         export_all_trees = 1;
549                         continue;
550                 }
551                 if (!strcmp(arg, "--")) {
552                         ok_paths = &argv[i+1];
553                         break;
554                 } else if (arg[0] != '-') {
555                         ok_paths = &argv[i];
556                         break;
557                 }
558
559                 usage(daemon_usage);
560         }
561
562         if (inetd_mode) {
563                 fclose(stderr); //FIXME: workaround
564                 return execute();
565         }
566
567         return serve(port);
568 }