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