daemon.con commit daemon: Set SO_REUSEADDR on listening sockets. (1955fab)
   1#include <signal.h>
   2#include <sys/wait.h>
   3#include <sys/socket.h>
   4#include <sys/time.h>
   5#include <sys/poll.h>
   6#include <netdb.h>
   7#include <netinet/in.h>
   8#include <arpa/inet.h>
   9#include <syslog.h>
  10#include "pkt-line.h"
  11#include "cache.h"
  12#include "exec_cmd.h"
  13
  14static int log_syslog;
  15static int verbose;
  16static int reuseaddr;
  17
  18static const char daemon_usage[] =
  19"git-daemon [--verbose] [--syslog] [--inetd | --port=n] [--export-all]\n"
  20"           [--timeout=n] [--init-timeout=n] [--strict-paths]\n"
  21"           [--base-path=path] [--reuseaddr] [directory...]";
  22
  23/* List of acceptable pathname prefixes */
  24static char **ok_paths = NULL;
  25static int strict_paths = 0;
  26
  27/* If this is set, git-daemon-export-ok is not required */
  28static int export_all_trees = 0;
  29
  30/* Take all paths relative to this one if non-NULL */
  31static char *base_path = NULL;
  32
  33/* Timeout, and initial timeout */
  34static unsigned int timeout = 0;
  35static unsigned int init_timeout = 0;
  36
  37static void logreport(int priority, const char *err, va_list params)
  38{
  39        /* We should do a single write so that it is atomic and output
  40         * of several processes do not get intermingled. */
  41        char buf[1024];
  42        int buflen;
  43        int maxlen, msglen;
  44
  45        /* sizeof(buf) should be big enough for "[pid] \n" */
  46        buflen = snprintf(buf, sizeof(buf), "[%ld] ", (long) getpid());
  47
  48        maxlen = sizeof(buf) - buflen - 1; /* -1 for our own LF */
  49        msglen = vsnprintf(buf + buflen, maxlen, err, params);
  50
  51        if (log_syslog) {
  52                syslog(priority, "%s", buf);
  53                return;
  54        }
  55
  56        /* maxlen counted our own LF but also counts space given to
  57         * vsnprintf for the terminating NUL.  We want to make sure that
  58         * we have space for our own LF and NUL after the "meat" of the
  59         * message, so truncate it at maxlen - 1.
  60         */
  61        if (msglen > maxlen - 1)
  62                msglen = maxlen - 1;
  63        else if (msglen < 0)
  64                msglen = 0; /* Protect against weird return values. */
  65        buflen += msglen;
  66
  67        buf[buflen++] = '\n';
  68        buf[buflen] = '\0';
  69
  70        write(2, buf, buflen);
  71}
  72
  73static void logerror(const char *err, ...)
  74{
  75        va_list params;
  76        va_start(params, err);
  77        logreport(LOG_ERR, err, params);
  78        va_end(params);
  79}
  80
  81static void loginfo(const char *err, ...)
  82{
  83        va_list params;
  84        if (!verbose)
  85                return;
  86        va_start(params, err);
  87        logreport(LOG_INFO, err, params);
  88        va_end(params);
  89}
  90
  91static int avoid_alias(char *p)
  92{
  93        int sl, ndot;
  94
  95        /* 
  96         * This resurrects the belts and suspenders paranoia check by HPA
  97         * done in <435560F7.4080006@zytor.com> thread, now enter_repo()
  98         * does not do getcwd() based path canonicalizations.
  99         *
 100         * sl becomes true immediately after seeing '/' and continues to
 101         * be true as long as dots continue after that without intervening
 102         * non-dot character.
 103         */
 104        if (!p || (*p != '/' && *p != '~'))
 105                return -1;
 106        sl = 1; ndot = 0;
 107        p++;
 108
 109        while (1) {
 110                char ch = *p++;
 111                if (sl) {
 112                        if (ch == '.')
 113                                ndot++;
 114                        else if (ch == '/') {
 115                                if (ndot < 3)
 116                                        /* reject //, /./ and /../ */
 117                                        return -1;
 118                                ndot = 0;
 119                        }
 120                        else if (ch == 0) {
 121                                if (0 < ndot && ndot < 3)
 122                                        /* reject /.$ and /..$ */
 123                                        return -1;
 124                                return 0;
 125                        }
 126                        else
 127                                sl = ndot = 0;
 128                }
 129                else if (ch == 0)
 130                        return 0;
 131                else if (ch == '/') {
 132                        sl = 1;
 133                        ndot = 0;
 134                }
 135        }
 136}
 137
 138static char *path_ok(char *dir)
 139{
 140        char *path;
 141
 142        if (avoid_alias(dir)) {
 143                logerror("'%s': aliased", dir);
 144                return NULL;
 145        }
 146
 147        if (base_path) {
 148                static char rpath[PATH_MAX];
 149                if (!strict_paths && *dir == '~')
 150                        ; /* allow user relative paths */
 151                else if (*dir != '/') {
 152                        /* otherwise allow only absolute */
 153                        logerror("'%s': Non-absolute path denied (base-path active)", dir);
 154                        return NULL;
 155                }
 156                else {
 157                        snprintf(rpath, PATH_MAX, "%s%s", base_path, dir);
 158                        dir = rpath;
 159                }
 160        }
 161
 162        path = enter_repo(dir, strict_paths);
 163
 164        if (!path) {
 165                logerror("'%s': unable to chdir or not a git archive", dir);
 166                return NULL;
 167        }
 168
 169        if ( ok_paths && *ok_paths ) {
 170                char **pp;
 171                int pathlen = strlen(path);
 172
 173                /* The validation is done on the paths after enter_repo
 174                 * appends optional {.git,.git/.git} and friends, but 
 175                 * it does not use getcwd().  So if your /pub is
 176                 * a symlink to /mnt/pub, you can whitelist /pub and
 177                 * do not have to say /mnt/pub.
 178                 * Do not say /pub/.
 179                 */
 180                for ( pp = ok_paths ; *pp ; pp++ ) {
 181                        int len = strlen(*pp);
 182                        if (len <= pathlen &&
 183                            !memcmp(*pp, path, len) &&
 184                            (path[len] == '\0' ||
 185                             (!strict_paths && path[len] == '/')))
 186                                return path;
 187                }
 188        }
 189        else {
 190                /* be backwards compatible */
 191                if (!strict_paths)
 192                        return path;
 193        }
 194
 195        logerror("'%s': not in whitelist", path);
 196        return NULL;            /* Fallthrough. Deny by default */
 197}
 198
 199static int upload(char *dir)
 200{
 201        /* Timeout as string */
 202        char timeout_buf[64];
 203        const char *path;
 204
 205        loginfo("Request for '%s'", dir);
 206
 207        if (!(path = path_ok(dir)))
 208                return -1;
 209
 210        /*
 211         * Security on the cheap.
 212         *
 213         * We want a readable HEAD, usable "objects" directory, and
 214         * a "git-daemon-export-ok" flag that says that the other side
 215         * is ok with us doing this.
 216         *
 217         * path_ok() uses enter_repo() and does whitelist checking.
 218         * We only need to make sure the repository is exported.
 219         */
 220
 221        if (!export_all_trees && access("git-daemon-export-ok", F_OK)) {
 222                logerror("'%s': repository not exported.", path);
 223                errno = EACCES;
 224                return -1;
 225        }
 226
 227        /*
 228         * We'll ignore SIGTERM from now on, we have a
 229         * good client.
 230         */
 231        signal(SIGTERM, SIG_IGN);
 232
 233        snprintf(timeout_buf, sizeof timeout_buf, "--timeout=%u", timeout);
 234
 235        /* git-upload-pack only ever reads stuff, so this is safe */
 236        execl_git_cmd("upload-pack", "--strict", timeout_buf, ".", NULL);
 237        return -1;
 238}
 239
 240static int execute(void)
 241{
 242        static char line[1000];
 243        int len;
 244
 245        alarm(init_timeout ? init_timeout : timeout);
 246        len = packet_read_line(0, line, sizeof(line));
 247        alarm(0);
 248
 249        if (len && line[len-1] == '\n')
 250                line[--len] = 0;
 251
 252        if (!strncmp("git-upload-pack ", line, 16))
 253                return upload(line+16);
 254
 255        logerror("Protocol error: '%s'", line);
 256        return -1;
 257}
 258
 259
 260/*
 261 * We count spawned/reaped separately, just to avoid any
 262 * races when updating them from signals. The SIGCHLD handler
 263 * will only update children_reaped, and the fork logic will
 264 * only update children_spawned.
 265 *
 266 * MAX_CHILDREN should be a power-of-two to make the modulus
 267 * operation cheap. It should also be at least twice
 268 * the maximum number of connections we will ever allow.
 269 */
 270#define MAX_CHILDREN 128
 271
 272static int max_connections = 25;
 273
 274/* These are updated by the signal handler */
 275static volatile unsigned int children_reaped = 0;
 276static pid_t dead_child[MAX_CHILDREN];
 277
 278/* These are updated by the main loop */
 279static unsigned int children_spawned = 0;
 280static unsigned int children_deleted = 0;
 281
 282static struct child {
 283        pid_t pid;
 284        int addrlen;
 285        struct sockaddr_storage address;
 286} live_child[MAX_CHILDREN];
 287
 288static void add_child(int idx, pid_t pid, struct sockaddr *addr, int addrlen)
 289{
 290        live_child[idx].pid = pid;
 291        live_child[idx].addrlen = addrlen;
 292        memcpy(&live_child[idx].address, addr, addrlen);
 293}
 294
 295/*
 296 * Walk from "deleted" to "spawned", and remove child "pid".
 297 *
 298 * We move everything up by one, since the new "deleted" will
 299 * be one higher.
 300 */
 301static void remove_child(pid_t pid, unsigned deleted, unsigned spawned)
 302{
 303        struct child n;
 304
 305        deleted %= MAX_CHILDREN;
 306        spawned %= MAX_CHILDREN;
 307        if (live_child[deleted].pid == pid) {
 308                live_child[deleted].pid = -1;
 309                return;
 310        }
 311        n = live_child[deleted];
 312        for (;;) {
 313                struct child m;
 314                deleted = (deleted + 1) % MAX_CHILDREN;
 315                if (deleted == spawned)
 316                        die("could not find dead child %d\n", pid);
 317                m = live_child[deleted];
 318                live_child[deleted] = n;
 319                if (m.pid == pid)
 320                        return;
 321                n = m;
 322        }
 323}
 324
 325/*
 326 * This gets called if the number of connections grows
 327 * past "max_connections".
 328 *
 329 * We _should_ start off by searching for connections
 330 * from the same IP, and if there is some address wth
 331 * multiple connections, we should kill that first.
 332 *
 333 * As it is, we just "randomly" kill 25% of the connections,
 334 * and our pseudo-random generator sucks too. I have no
 335 * shame.
 336 *
 337 * Really, this is just a place-holder for a _real_ algorithm.
 338 */
 339static void kill_some_children(int signo, unsigned start, unsigned stop)
 340{
 341        start %= MAX_CHILDREN;
 342        stop %= MAX_CHILDREN;
 343        while (start != stop) {
 344                if (!(start & 3))
 345                        kill(live_child[start].pid, signo);
 346                start = (start + 1) % MAX_CHILDREN;
 347        }
 348}
 349
 350static void check_max_connections(void)
 351{
 352        for (;;) {
 353                int active;
 354                unsigned spawned, reaped, deleted;
 355
 356                spawned = children_spawned;
 357                reaped = children_reaped;
 358                deleted = children_deleted;
 359
 360                while (deleted < reaped) {
 361                        pid_t pid = dead_child[deleted % MAX_CHILDREN];
 362                        remove_child(pid, deleted, spawned);
 363                        deleted++;
 364                }
 365                children_deleted = deleted;
 366
 367                active = spawned - deleted;
 368                if (active <= max_connections)
 369                        break;
 370
 371                /* Kill some unstarted connections with SIGTERM */
 372                kill_some_children(SIGTERM, deleted, spawned);
 373                if (active <= max_connections << 1)
 374                        break;
 375
 376                /* If the SIGTERM thing isn't helping use SIGKILL */
 377                kill_some_children(SIGKILL, deleted, spawned);
 378                sleep(1);
 379        }
 380}
 381
 382static void handle(int incoming, struct sockaddr *addr, int addrlen)
 383{
 384        pid_t pid = fork();
 385        char addrbuf[256] = "";
 386        int port = -1;
 387
 388        if (pid) {
 389                unsigned idx;
 390
 391                close(incoming);
 392                if (pid < 0)
 393                        return;
 394
 395                idx = children_spawned % MAX_CHILDREN;
 396                children_spawned++;
 397                add_child(idx, pid, addr, addrlen);
 398
 399                check_max_connections();
 400                return;
 401        }
 402
 403        dup2(incoming, 0);
 404        dup2(incoming, 1);
 405        close(incoming);
 406
 407        if (addr->sa_family == AF_INET) {
 408                struct sockaddr_in *sin_addr = (void *) addr;
 409                inet_ntop(AF_INET, &sin_addr->sin_addr, addrbuf, sizeof(addrbuf));
 410                port = sin_addr->sin_port;
 411
 412#ifndef NO_IPV6
 413        } else if (addr->sa_family == AF_INET6) {
 414                struct sockaddr_in6 *sin6_addr = (void *) addr;
 415
 416                char *buf = addrbuf;
 417                *buf++ = '['; *buf = '\0'; /* stpcpy() is cool */
 418                inet_ntop(AF_INET6, &sin6_addr->sin6_addr, buf, sizeof(addrbuf) - 1);
 419                strcat(buf, "]");
 420
 421                port = sin6_addr->sin6_port;
 422#endif
 423        }
 424        loginfo("Connection from %s:%d", addrbuf, port);
 425
 426        exit(execute());
 427}
 428
 429static void child_handler(int signo)
 430{
 431        for (;;) {
 432                int status;
 433                pid_t pid = waitpid(-1, &status, WNOHANG);
 434
 435                if (pid > 0) {
 436                        unsigned reaped = children_reaped;
 437                        dead_child[reaped % MAX_CHILDREN] = pid;
 438                        children_reaped = reaped + 1;
 439                        /* XXX: Custom logging, since we don't wanna getpid() */
 440                        if (verbose) {
 441                                char *dead = "";
 442                                if (!WIFEXITED(status) || WEXITSTATUS(status) > 0)
 443                                        dead = " (with error)";
 444                                if (log_syslog)
 445                                        syslog(LOG_INFO, "[%d] Disconnected%s", pid, dead);
 446                                else
 447                                        fprintf(stderr, "[%d] Disconnected%s\n", pid, dead);
 448                        }
 449                        continue;
 450                }
 451                break;
 452        }
 453}
 454
 455static int set_reuse_addr(int sockfd)
 456{
 457        int on = 1;
 458
 459        if (!reuseaddr)
 460                return 0;
 461        return setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
 462                          &on, sizeof(on));
 463}
 464
 465#ifndef NO_IPV6
 466
 467static int socksetup(int port, int **socklist_p)
 468{
 469        int socknum = 0, *socklist = NULL;
 470        int maxfd = -1;
 471        char pbuf[NI_MAXSERV];
 472
 473        struct addrinfo hints, *ai0, *ai;
 474        int gai;
 475
 476        sprintf(pbuf, "%d", port);
 477        memset(&hints, 0, sizeof(hints));
 478        hints.ai_family = AF_UNSPEC;
 479        hints.ai_socktype = SOCK_STREAM;
 480        hints.ai_protocol = IPPROTO_TCP;
 481        hints.ai_flags = AI_PASSIVE;
 482
 483        gai = getaddrinfo(NULL, pbuf, &hints, &ai0);
 484        if (gai)
 485                die("getaddrinfo() failed: %s\n", gai_strerror(gai));
 486
 487        for (ai = ai0; ai; ai = ai->ai_next) {
 488                int sockfd;
 489                int *newlist;
 490
 491                sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
 492                if (sockfd < 0)
 493                        continue;
 494                if (sockfd >= FD_SETSIZE) {
 495                        error("too large socket descriptor.");
 496                        close(sockfd);
 497                        continue;
 498                }
 499
 500#ifdef IPV6_V6ONLY
 501                if (ai->ai_family == AF_INET6) {
 502                        int on = 1;
 503                        setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,
 504                                   &on, sizeof(on));
 505                        /* Note: error is not fatal */
 506                }
 507#endif
 508
 509                if (set_reuse_addr(sockfd)) {
 510                        close(sockfd);
 511                        return 0;       /* not fatal */
 512                }
 513
 514                if (bind(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) {
 515                        close(sockfd);
 516                        continue;       /* not fatal */
 517                }
 518                if (listen(sockfd, 5) < 0) {
 519                        close(sockfd);
 520                        continue;       /* not fatal */
 521                }
 522
 523                newlist = realloc(socklist, sizeof(int) * (socknum + 1));
 524                if (!newlist)
 525                        die("memory allocation failed: %s", strerror(errno));
 526
 527                socklist = newlist;
 528                socklist[socknum++] = sockfd;
 529
 530                if (maxfd < sockfd)
 531                        maxfd = sockfd;
 532        }
 533
 534        freeaddrinfo(ai0);
 535
 536        *socklist_p = socklist;
 537        return socknum;
 538}
 539
 540#else /* NO_IPV6 */
 541
 542static int socksetup(int port, int **socklist_p)
 543{
 544        struct sockaddr_in sin;
 545        int sockfd;
 546
 547        sockfd = socket(AF_INET, SOCK_STREAM, 0);
 548        if (sockfd < 0)
 549                return 0;
 550
 551        memset(&sin, 0, sizeof sin);
 552        sin.sin_family = AF_INET;
 553        sin.sin_addr.s_addr = htonl(INADDR_ANY);
 554        sin.sin_port = htons(port);
 555
 556        if (set_reuse_addr(sockfd)) {
 557                close(sockfd);
 558                return 0;
 559        }
 560
 561        if ( bind(sockfd, (struct sockaddr *)&sin, sizeof sin) < 0 ) {
 562                close(sockfd);
 563                return 0;
 564        }
 565
 566        if (listen(sockfd, 5) < 0) {
 567                close(sockfd);
 568                return 0;
 569        }
 570
 571        *socklist_p = xmalloc(sizeof(int));
 572        **socklist_p = sockfd;
 573        return 1;
 574}
 575
 576#endif
 577
 578static int service_loop(int socknum, int *socklist)
 579{
 580        struct pollfd *pfd;
 581        int i;
 582
 583        pfd = xcalloc(socknum, sizeof(struct pollfd));
 584
 585        for (i = 0; i < socknum; i++) {
 586                pfd[i].fd = socklist[i];
 587                pfd[i].events = POLLIN;
 588        }
 589
 590        signal(SIGCHLD, child_handler);
 591
 592        for (;;) {
 593                int i;
 594
 595                if (poll(pfd, socknum, -1) < 0) {
 596                        if (errno != EINTR) {
 597                                error("poll failed, resuming: %s",
 598                                      strerror(errno));
 599                                sleep(1);
 600                        }
 601                        continue;
 602                }
 603
 604                for (i = 0; i < socknum; i++) {
 605                        if (pfd[i].revents & POLLIN) {
 606                                struct sockaddr_storage ss;
 607                                unsigned int sslen = sizeof(ss);
 608                                int incoming = accept(pfd[i].fd, (struct sockaddr *)&ss, &sslen);
 609                                if (incoming < 0) {
 610                                        switch (errno) {
 611                                        case EAGAIN:
 612                                        case EINTR:
 613                                        case ECONNABORTED:
 614                                                continue;
 615                                        default:
 616                                                die("accept returned %s", strerror(errno));
 617                                        }
 618                                }
 619                                handle(incoming, (struct sockaddr *)&ss, sslen);
 620                        }
 621                }
 622        }
 623}
 624
 625static int serve(int port)
 626{
 627        int socknum, *socklist;
 628
 629        socknum = socksetup(port, &socklist);
 630        if (socknum == 0)
 631                die("unable to allocate any listen sockets on port %u", port);
 632
 633        return service_loop(socknum, socklist);
 634}
 635
 636int main(int argc, char **argv)
 637{
 638        int port = DEFAULT_GIT_PORT;
 639        int inetd_mode = 0;
 640        int i;
 641
 642        for (i = 1; i < argc; i++) {
 643                char *arg = argv[i];
 644
 645                if (!strncmp(arg, "--port=", 7)) {
 646                        char *end;
 647                        unsigned long n;
 648                        n = strtoul(arg+7, &end, 0);
 649                        if (arg[7] && !*end) {
 650                                port = n;
 651                                continue;
 652                        }
 653                }
 654                if (!strcmp(arg, "--inetd")) {
 655                        inetd_mode = 1;
 656                        log_syslog = 1;
 657                        continue;
 658                }
 659                if (!strcmp(arg, "--verbose")) {
 660                        verbose = 1;
 661                        continue;
 662                }
 663                if (!strcmp(arg, "--syslog")) {
 664                        log_syslog = 1;
 665                        continue;
 666                }
 667                if (!strcmp(arg, "--export-all")) {
 668                        export_all_trees = 1;
 669                        continue;
 670                }
 671                if (!strncmp(arg, "--timeout=", 10)) {
 672                        timeout = atoi(arg+10);
 673                        continue;
 674                }
 675                if (!strncmp(arg, "--init-timeout=", 15)) {
 676                        init_timeout = atoi(arg+15);
 677                        continue;
 678                }
 679                if (!strcmp(arg, "--strict-paths")) {
 680                        strict_paths = 1;
 681                        continue;
 682                }
 683                if (!strncmp(arg, "--base-path=", 12)) {
 684                        base_path = arg+12;
 685                        continue;
 686                }
 687                if (!strcmp(arg, "--reuseaddr")) {
 688                        reuseaddr = 1;
 689                        continue;
 690                }
 691                if (!strcmp(arg, "--")) {
 692                        ok_paths = &argv[i+1];
 693                        break;
 694                } else if (arg[0] != '-') {
 695                        ok_paths = &argv[i];
 696                        break;
 697                }
 698
 699                usage(daemon_usage);
 700        }
 701
 702        if (log_syslog)
 703                openlog("git-daemon", 0, LOG_DAEMON);
 704
 705        if (strict_paths && (!ok_paths || !*ok_paths)) {
 706                if (!inetd_mode)
 707                        die("git-daemon: option --strict-paths requires a whitelist");
 708
 709                logerror("option --strict-paths requires a whitelist");
 710                exit (1);
 711        }
 712
 713        if (inetd_mode) {
 714                fclose(stderr); //FIXME: workaround
 715                return execute();
 716        }
 717
 718        return serve(port);
 719}