credential-cache--daemon.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. #include "builtin.h"
  2. #include "parse-options.h"
  3. #ifndef NO_UNIX_SOCKETS
  4. #include "config.h"
  5. #include "tempfile.h"
  6. #include "credential.h"
  7. #include "unix-socket.h"
  8. struct credential_cache_entry {
  9. struct credential item;
  10. timestamp_t expiration;
  11. };
  12. static struct credential_cache_entry *entries;
  13. static int entries_nr;
  14. static int entries_alloc;
  15. static void cache_credential(struct credential *c, int timeout)
  16. {
  17. struct credential_cache_entry *e;
  18. ALLOC_GROW(entries, entries_nr + 1, entries_alloc);
  19. e = &entries[entries_nr++];
  20. /* take ownership of pointers */
  21. memcpy(&e->item, c, sizeof(*c));
  22. memset(c, 0, sizeof(*c));
  23. e->expiration = time(NULL) + timeout;
  24. }
  25. static struct credential_cache_entry *lookup_credential(const struct credential *c)
  26. {
  27. int i;
  28. for (i = 0; i < entries_nr; i++) {
  29. struct credential *e = &entries[i].item;
  30. if (credential_match(c, e))
  31. return &entries[i];
  32. }
  33. return NULL;
  34. }
  35. static void remove_credential(const struct credential *c)
  36. {
  37. struct credential_cache_entry *e;
  38. e = lookup_credential(c);
  39. if (e)
  40. e->expiration = 0;
  41. }
  42. static timestamp_t check_expirations(void)
  43. {
  44. static timestamp_t wait_for_entry_until;
  45. int i = 0;
  46. timestamp_t now = time(NULL);
  47. timestamp_t next = TIME_MAX;
  48. /*
  49. * Initially give the client 30 seconds to actually contact us
  50. * and store a credential before we decide there's no point in
  51. * keeping the daemon around.
  52. */
  53. if (!wait_for_entry_until)
  54. wait_for_entry_until = now + 30;
  55. while (i < entries_nr) {
  56. if (entries[i].expiration <= now) {
  57. entries_nr--;
  58. credential_clear(&entries[i].item);
  59. if (i != entries_nr)
  60. memcpy(&entries[i], &entries[entries_nr], sizeof(*entries));
  61. /*
  62. * Stick around 30 seconds in case a new credential
  63. * shows up (e.g., because we just removed a failed
  64. * one, and we will soon get the correct one).
  65. */
  66. wait_for_entry_until = now + 30;
  67. }
  68. else {
  69. if (entries[i].expiration < next)
  70. next = entries[i].expiration;
  71. i++;
  72. }
  73. }
  74. if (!entries_nr) {
  75. if (wait_for_entry_until <= now)
  76. return 0;
  77. next = wait_for_entry_until;
  78. }
  79. return next - now;
  80. }
  81. static int read_request(FILE *fh, struct credential *c,
  82. struct strbuf *action, int *timeout)
  83. {
  84. static struct strbuf item = STRBUF_INIT;
  85. const char *p;
  86. strbuf_getline_lf(&item, fh);
  87. if (!skip_prefix(item.buf, "action=", &p))
  88. return error("client sent bogus action line: %s", item.buf);
  89. strbuf_addstr(action, p);
  90. strbuf_getline_lf(&item, fh);
  91. if (!skip_prefix(item.buf, "timeout=", &p))
  92. return error("client sent bogus timeout line: %s", item.buf);
  93. *timeout = atoi(p);
  94. if (credential_read(c, fh) < 0)
  95. return -1;
  96. return 0;
  97. }
  98. static void serve_one_client(FILE *in, FILE *out)
  99. {
  100. struct credential c = CREDENTIAL_INIT;
  101. struct strbuf action = STRBUF_INIT;
  102. int timeout = -1;
  103. if (read_request(in, &c, &action, &timeout) < 0)
  104. /* ignore error */ ;
  105. else if (!strcmp(action.buf, "get")) {
  106. struct credential_cache_entry *e = lookup_credential(&c);
  107. if (e) {
  108. fprintf(out, "username=%s\n", e->item.username);
  109. fprintf(out, "password=%s\n", e->item.password);
  110. }
  111. }
  112. else if (!strcmp(action.buf, "exit")) {
  113. /*
  114. * It's important that we clean up our socket first, and then
  115. * signal the client only once we have finished the cleanup.
  116. * Calling exit() directly does this, because we clean up in
  117. * our atexit() handler, and then signal the client when our
  118. * process actually ends, which closes the socket and gives
  119. * them EOF.
  120. */
  121. exit(0);
  122. }
  123. else if (!strcmp(action.buf, "erase"))
  124. remove_credential(&c);
  125. else if (!strcmp(action.buf, "store")) {
  126. if (timeout < 0)
  127. warning("cache client didn't specify a timeout");
  128. else if (!c.username || !c.password)
  129. warning("cache client gave us a partial credential");
  130. else {
  131. remove_credential(&c);
  132. cache_credential(&c, timeout);
  133. }
  134. }
  135. else
  136. warning("cache client sent unknown action: %s", action.buf);
  137. credential_clear(&c);
  138. strbuf_release(&action);
  139. }
  140. static int serve_cache_loop(int fd)
  141. {
  142. struct pollfd pfd;
  143. timestamp_t wakeup;
  144. wakeup = check_expirations();
  145. if (!wakeup)
  146. return 0;
  147. pfd.fd = fd;
  148. pfd.events = POLLIN;
  149. if (poll(&pfd, 1, 1000 * wakeup) < 0) {
  150. if (errno != EINTR)
  151. die_errno("poll failed");
  152. return 1;
  153. }
  154. if (pfd.revents & POLLIN) {
  155. int client, client2;
  156. FILE *in, *out;
  157. client = accept(fd, NULL, NULL);
  158. if (client < 0) {
  159. warning_errno("accept failed");
  160. return 1;
  161. }
  162. client2 = dup(client);
  163. if (client2 < 0) {
  164. warning_errno("dup failed");
  165. close(client);
  166. return 1;
  167. }
  168. in = xfdopen(client, "r");
  169. out = xfdopen(client2, "w");
  170. serve_one_client(in, out);
  171. fclose(in);
  172. fclose(out);
  173. }
  174. return 1;
  175. }
  176. static void serve_cache(const char *socket_path, int debug)
  177. {
  178. int fd;
  179. fd = unix_stream_listen(socket_path);
  180. if (fd < 0)
  181. die_errno("unable to bind to '%s'", socket_path);
  182. printf("ok\n");
  183. fclose(stdout);
  184. if (!debug) {
  185. if (!freopen("/dev/null", "w", stderr))
  186. die_errno("unable to point stderr to /dev/null");
  187. }
  188. while (serve_cache_loop(fd))
  189. ; /* nothing */
  190. close(fd);
  191. }
  192. static const char permissions_advice[] = N_(
  193. "The permissions on your socket directory are too loose; other\n"
  194. "users may be able to read your cached credentials. Consider running:\n"
  195. "\n"
  196. " chmod 0700 %s");
  197. static void init_socket_directory(const char *path)
  198. {
  199. struct stat st;
  200. char *path_copy = xstrdup(path);
  201. char *dir = dirname(path_copy);
  202. if (!stat(dir, &st)) {
  203. if (st.st_mode & 077)
  204. die(_(permissions_advice), dir);
  205. } else {
  206. /*
  207. * We must be sure to create the directory with the correct mode,
  208. * not just chmod it after the fact; otherwise, there is a race
  209. * condition in which somebody can chdir to it, sleep, then try to open
  210. * our protected socket.
  211. */
  212. if (safe_create_leading_directories_const(dir) < 0)
  213. die_errno("unable to create directories for '%s'", dir);
  214. if (mkdir(dir, 0700) < 0)
  215. die_errno("unable to mkdir '%s'", dir);
  216. }
  217. if (chdir(dir))
  218. /*
  219. * We don't actually care what our cwd is; we chdir here just to
  220. * be a friendly daemon and avoid tying up our original cwd.
  221. * If this fails, it's OK to just continue without that benefit.
  222. */
  223. ;
  224. free(path_copy);
  225. }
  226. int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix)
  227. {
  228. struct tempfile *socket_file;
  229. const char *socket_path;
  230. int ignore_sighup = 0;
  231. static const char *usage[] = {
  232. "git-credential-cache--daemon [opts] <socket_path>",
  233. NULL
  234. };
  235. int debug = 0;
  236. const struct option options[] = {
  237. OPT_BOOL(0, "debug", &debug,
  238. N_("print debugging messages to stderr")),
  239. OPT_END()
  240. };
  241. git_config_get_bool("credentialcache.ignoresighup", &ignore_sighup);
  242. argc = parse_options(argc, argv, prefix, options, usage, 0);
  243. socket_path = argv[0];
  244. if (!socket_path)
  245. usage_with_options(usage, options);
  246. if (!is_absolute_path(socket_path))
  247. die("socket directory must be an absolute path");
  248. init_socket_directory(socket_path);
  249. socket_file = register_tempfile(socket_path);
  250. if (ignore_sighup)
  251. signal(SIGHUP, SIG_IGN);
  252. serve_cache(socket_path, debug);
  253. delete_tempfile(&socket_file);
  254. return 0;
  255. }
  256. #else
  257. int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix)
  258. {
  259. const char * const usage[] = {
  260. "git credential-cache--daemon [options] <action>",
  261. "",
  262. "credential-cache--daemon is disabled in this build of Git",
  263. NULL
  264. };
  265. struct option options[] = { OPT_END() };
  266. argc = parse_options(argc, argv, prefix, options, usage, 0);
  267. die(_("credential-cache--daemon unavailable; no unix socket support"));
  268. }
  269. #endif /* NO_UNIX_SOCKET */