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