submodule-config: verify submodule names as paths
[gitweb.git] / credential-cache--daemon.c
index eef6fce4c72ab37d75a0f75129666009a6a1ee54..46c5937526a53c3563ea47bfba8195bcf9352c35 100644 (file)
@@ -2,7 +2,6 @@
 #include "tempfile.h"
 #include "credential.h"
 #include "unix-socket.h"
-#include "sigchain.h"
 #include "parse-options.h"
 
 static struct tempfile socket_file;
@@ -97,12 +96,12 @@ static int read_request(FILE *fh, struct credential *c,
        static struct strbuf item = STRBUF_INIT;
        const char *p;
 
-       strbuf_getline(&item, fh, '\n');
+       strbuf_getline_lf(&item, fh);
        if (!skip_prefix(item.buf, "action=", &p))
                return error("client sent bogus action line: %s", item.buf);
        strbuf_addstr(action, p);
 
-       strbuf_getline(&item, fh, '\n');
+       strbuf_getline_lf(&item, fh);
        if (!skip_prefix(item.buf, "timeout=", &p))
                return error("client sent bogus timeout line: %s", item.buf);
        *timeout = atoi(p);
@@ -127,8 +126,17 @@ static void serve_one_client(FILE *in, FILE *out)
                        fprintf(out, "password=%s\n", e->item.password);
                }
        }
-       else if (!strcmp(action.buf, "exit"))
+       else if (!strcmp(action.buf, "exit")) {
+               /*
+                * It's important that we clean up our socket first, and then
+                * signal the client only once we have finished the cleanup.
+                * Calling exit() directly does this, because we clean up in
+                * our atexit() handler, and then signal the client when our
+                * process actually ends, which closes the socket and gives
+                * them EOF.
+                */
                exit(0);
+       }
        else if (!strcmp(action.buf, "erase"))
                remove_credential(&c);
        else if (!strcmp(action.buf, "store")) {
@@ -171,12 +179,12 @@ static int serve_cache_loop(int fd)
 
                client = accept(fd, NULL, NULL);
                if (client < 0) {
-                       warning("accept failed: %s", strerror(errno));
+                       warning_errno("accept failed");
                        return 1;
                }
                client2 = dup(client);
                if (client2 < 0) {
-                       warning("dup failed: %s", strerror(errno));
+                       warning_errno("dup failed");
                        close(client);
                        return 1;
                }
@@ -211,12 +219,12 @@ static void serve_cache(const char *socket_path, int debug)
        close(fd);
 }
 
-static const char permissions_advice[] =
+static const char permissions_advice[] = N_(
 "The permissions on your socket directory are too loose; other\n"
 "users may be able to read your cached credentials. Consider running:\n"
 "\n"
-"      chmod 0700 %s";
-static void check_socket_directory(const char *path)
+"      chmod 0700 %s");
+static void init_socket_directory(const char *path)
 {
        struct stat st;
        char *path_copy = xstrdup(path);
@@ -224,27 +232,35 @@ static void check_socket_directory(const char *path)
 
        if (!stat(dir, &st)) {
                if (st.st_mode & 077)
-                       die(permissions_advice, dir);
-               free(path_copy);
-               return;
+                       die(_(permissions_advice), dir);
+       } else {
+               /*
+                * We must be sure to create the directory with the correct mode,
+                * not just chmod it after the fact; otherwise, there is a race
+                * condition in which somebody can chdir to it, sleep, then try to open
+                * our protected socket.
+                */
+               if (safe_create_leading_directories_const(dir) < 0)
+                       die_errno("unable to create directories for '%s'", dir);
+               if (mkdir(dir, 0700) < 0)
+                       die_errno("unable to mkdir '%s'", dir);
        }
 
-       /*
-        * We must be sure to create the directory with the correct mode,
-        * not just chmod it after the fact; otherwise, there is a race
-        * condition in which somebody can chdir to it, sleep, then try to open
-        * our protected socket.
-        */
-       if (safe_create_leading_directories_const(dir) < 0)
-               die_errno("unable to create directories for '%s'", dir);
-       if (mkdir(dir, 0700) < 0)
-               die_errno("unable to mkdir '%s'", dir);
+       if (chdir(dir))
+               /*
+                * We don't actually care what our cwd is; we chdir here just to
+                * be a friendly daemon and avoid tying up our original cwd.
+                * If this fails, it's OK to just continue without that benefit.
+                */
+               ;
+
        free(path_copy);
 }
 
-int main(int argc, const char **argv)
+int cmd_main(int argc, const char **argv)
 {
        const char *socket_path;
+       int ignore_sighup = 0;
        static const char *usage[] = {
                "git-credential-cache--daemon [opts] <socket_path>",
                NULL
@@ -256,14 +272,23 @@ int main(int argc, const char **argv)
                OPT_END()
        };
 
+       git_config_get_bool("credentialcache.ignoresighup", &ignore_sighup);
+
        argc = parse_options(argc, argv, NULL, options, usage, 0);
        socket_path = argv[0];
 
        if (!socket_path)
                usage_with_options(usage, options);
 
-       check_socket_directory(socket_path);
+       if (!is_absolute_path(socket_path))
+               die("socket directory must be an absolute path");
+
+       init_socket_directory(socket_path);
        register_tempfile(&socket_file, socket_path);
+
+       if (ignore_sighup)
+               signal(SIGHUP, SIG_IGN);
+
        serve_cache(socket_path, debug);
        delete_tempfile(&socket_file);