Merge branch 'fixes'
authorJunio C Hamano <junkio@cox.net>
Fri, 21 Oct 2005 06:19:47 +0000 (23:19 -0700)
committerJunio C Hamano <junkio@cox.net>
Fri, 21 Oct 2005 06:19:47 +0000 (23:19 -0700)
1  2 
daemon.c
diff --combined daemon.c
index 8bb4d913bd3362314bdc936fe52946c82cf90c4a,cec7e75d5ec6be6f14572592024f2461194b7369..bd278b01c11ed831623e3c6db111f53c2e08d050
+++ b/daemon.c
@@@ -12,9 -12,7 +12,9 @@@
  static int log_syslog;
  static int verbose;
  
 -static const char daemon_usage[] = "git-daemon [--verbose] [--syslog] [--inetd | --port=n] [--export-all] [directory...]";
 +static const char daemon_usage[] =
 +"git-daemon [--verbose] [--syslog] [--inetd | --port=n] [--export-all]\n"
 +"           [--timeout=n] [--init-timeout=n] [directory...]";
  
  /* List of acceptable pathname prefixes */
  static char **ok_paths = NULL;
@@@ -22,9 -20,6 +22,9 @@@
  /* If this is set, git-daemon-export-ok is not required */
  static int export_all_trees = 0;
  
 +/* Timeout, and initial timeout */
 +static unsigned int timeout = 0;
 +static unsigned int init_timeout = 0;
  
  static void logreport(int priority, const char *err, va_list params)
  {
@@@ -84,30 -79,17 +84,30 @@@ static int path_ok(const char *dir
  {
        const char *p = dir;
        char **pp;
 -      int sl = 1, ndot = 0;
 +      int sl, ndot;
 +
 +      /* The pathname here should be an absolute path. */
 +      if ( *p++ != '/' )
 +              return 0;
 +
 +      sl = 1;  ndot = 0;
  
        for (;;) {
                if ( *p == '.' ) {
                        ndot++;
 -              } else if ( *p == '/' || *p == '\0' ) {
 +              } else if ( *p == '\0' ) {
 +                      /* Reject "." and ".." at the end of the path */
                        if ( sl && ndot > 0 && ndot < 3 )
 -                              return 0; /* . or .. in path */
 +                              return 0;
 +
 +                      /* Otherwise OK */
 +                      break;
 +              } else if ( *p == '/' ) {
 +                      /* Refuse "", "." or ".." */
 +                      if ( sl && ndot < 3 )
 +                              return 0;
                        sl = 1;
 -                      if ( *p == '\0' )
 -                              break; /* End of string and all is good */
 +                      ndot = 0;
                } else {
                        sl = ndot = 0;
                }
  
        if ( ok_paths && *ok_paths ) {
                int ok = 0;
 -              int dirlen = strlen(dir); /* read_packet_line can return embedded \0 */
 +              int dirlen = strlen(dir);
  
                for ( pp = ok_paths ; *pp ; pp++ ) {
                        int len = strlen(*pp);
        return 1;               /* Path acceptable */
  }
  
 -static int upload(char *dir, int dirlen)
 +static int set_dir(const char *dir)
  {
 -      loginfo("Request for '%s'", dir);
 -
        if (!path_ok(dir)) {
 -              logerror("Forbidden directory: %s\n", dir);
 +              errno = EACCES;
                return -1;
        }
  
 -      if (chdir(dir) < 0) {
 -              logerror("Cannot chdir('%s'): %s", dir, strerror(errno));
 +      if ( chdir(dir) )
                return -1;
 -      }
 -
 -      chdir(".git");
 -
 +      
        /*
         * Security on the cheap.
         *
-        * We want a readable HEAD, usable "objects" directory, and 
+        * We want a readable HEAD, usable "objects" directory, and
         * a "git-daemon-export-ok" flag that says that the other side
         * is ok with us doing this.
         */
 -      if ((!export_all_trees && access("git-daemon-export-ok", F_OK)) ||
 -          access("objects/00", X_OK) ||
 -          access("HEAD", R_OK)) {
 -              logerror("Not a valid git-daemon-enabled repository: '%s'", dir);
 +      if (!export_all_trees && access("git-daemon-export-ok", F_OK)) {
 +              errno = EACCES;
 +              return -1;
 +      }
 +
 +      if (access("objects/", X_OK) || access("HEAD", R_OK)) {
 +              errno = EINVAL;
 +              return -1;
 +      }
 +
 +      /* If all this passed, we're OK */
 +      return 0;
 +}
 +
 +static int upload(char *dir)
 +{
 +      /* Try paths in this order */
 +      static const char *paths[] = { "%s", "%s/.git", "%s.git", "%s.git/.git", NULL };
 +      const char **pp;
 +      /* Enough for the longest path above including final null */
 +      int buflen = strlen(dir)+10;
 +      char *dirbuf = xmalloc(buflen);
 +      /* Timeout as string */
 +      char timeout_buf[64];
 +
 +      loginfo("Request for '%s'", dir);
 +
 +      for ( pp = paths ; *pp ; pp++ ) {
 +              snprintf(dirbuf, buflen, *pp, dir);
 +              if ( !set_dir(dirbuf) )
 +                      break;
 +      }
 +
 +      if ( !*pp ) {
 +              logerror("Cannot set directory '%s': %s", dir, strerror(errno));
                return -1;
        }
  
         */
        signal(SIGTERM, SIG_IGN);
  
 +      snprintf(timeout_buf, sizeof timeout_buf, "--timeout=%u", timeout);
 +
        /* git-upload-pack only ever reads stuff, so this is safe */
 -      execlp("git-upload-pack", "git-upload-pack", ".", NULL);
 +      execlp("git-upload-pack", "git-upload-pack", "--strict", timeout_buf, ".", NULL);
        return -1;
  }
  
@@@ -208,15 -163,13 +208,15 @@@ static int execute(void
        static char line[1000];
        int len;
  
 +      alarm(init_timeout ? init_timeout : timeout);
        len = packet_read_line(0, line, sizeof(line));
 +      alarm(0);
  
        if (len && line[len-1] == '\n')
                line[--len] = 0;
  
        if (!strncmp("git-upload-pack /", line, 17))
 -              return upload(line + 16, len - 16);
 +              return upload(line+16);
  
        logerror("Protocol error: '%s'", line);
        return -1;
@@@ -491,7 -444,7 +491,7 @@@ static int serve(int port
        for (;;) {
                int i;
                fds = fds_init;
-               
                if (select(maxfd + 1, &fds, NULL, NULL, NULL) < 0) {
                        if (errno != EINTR) {
                                error("select failed, resuming: %s",
@@@ -559,12 -512,6 +559,12 @@@ int main(int argc, char **argv
                        export_all_trees = 1;
                        continue;
                }
 +              if (!strncmp(arg, "--timeout=", 10)) {
 +                      timeout = atoi(arg+10);
 +              }
 +              if (!strncmp(arg, "--init-timeout=", 15)) {
 +                      init_timeout = atoi(arg+15);
 +              }
                if (!strcmp(arg, "--")) {
                        ok_paths = &argv[i+1];
                        break;