THIS IS A TEST INSTANCE ONLY! REPOSITORIES CAN BE DELETED AT ANY TIME!

Git Source Code Mirror - This is a publish-only repository and all pull requests are ignored. Please follow Documentation/SubmittingPatches procedure for any of your improvements.
git
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

196 lines
5.1KB

  1. #include "cache.h"
  2. #include "lockfile.h"
  3. #include "credential.h"
  4. #include "string-list.h"
  5. #include "parse-options.h"
  6. static struct lock_file credential_lock;
  7. static int parse_credential_file(const char *fn,
  8. struct credential *c,
  9. void (*match_cb)(struct credential *),
  10. void (*other_cb)(struct strbuf *))
  11. {
  12. FILE *fh;
  13. struct strbuf line = STRBUF_INIT;
  14. struct credential entry = CREDENTIAL_INIT;
  15. int found_credential = 0;
  16. fh = fopen(fn, "r");
  17. if (!fh) {
  18. if (errno != ENOENT && errno != EACCES)
  19. die_errno("unable to open %s", fn);
  20. return found_credential;
  21. }
  22. while (strbuf_getline_lf(&line, fh) != EOF) {
  23. credential_from_url(&entry, line.buf);
  24. if (entry.username && entry.password &&
  25. credential_match(c, &entry)) {
  26. found_credential = 1;
  27. if (match_cb) {
  28. match_cb(&entry);
  29. break;
  30. }
  31. }
  32. else if (other_cb)
  33. other_cb(&line);
  34. }
  35. credential_clear(&entry);
  36. strbuf_release(&line);
  37. fclose(fh);
  38. return found_credential;
  39. }
  40. static void print_entry(struct credential *c)
  41. {
  42. printf("username=%s\n", c->username);
  43. printf("password=%s\n", c->password);
  44. }
  45. static void print_line(struct strbuf *buf)
  46. {
  47. strbuf_addch(buf, '\n');
  48. write_or_die(get_lock_file_fd(&credential_lock), buf->buf, buf->len);
  49. }
  50. static void rewrite_credential_file(const char *fn, struct credential *c,
  51. struct strbuf *extra)
  52. {
  53. if (hold_lock_file_for_update(&credential_lock, fn, 0) < 0)
  54. die_errno("unable to get credential storage lock");
  55. if (extra)
  56. print_line(extra);
  57. parse_credential_file(fn, c, NULL, print_line);
  58. if (commit_lock_file(&credential_lock) < 0)
  59. die_errno("unable to write credential store");
  60. }
  61. static void store_credential_file(const char *fn, struct credential *c)
  62. {
  63. struct strbuf buf = STRBUF_INIT;
  64. strbuf_addf(&buf, "%s://", c->protocol);
  65. strbuf_addstr_urlencode(&buf, c->username, is_rfc3986_unreserved);
  66. strbuf_addch(&buf, ':');
  67. strbuf_addstr_urlencode(&buf, c->password, is_rfc3986_unreserved);
  68. strbuf_addch(&buf, '@');
  69. if (c->host)
  70. strbuf_addstr_urlencode(&buf, c->host, is_rfc3986_unreserved);
  71. if (c->path) {
  72. strbuf_addch(&buf, '/');
  73. strbuf_addstr_urlencode(&buf, c->path,
  74. is_rfc3986_reserved_or_unreserved);
  75. }
  76. rewrite_credential_file(fn, c, &buf);
  77. strbuf_release(&buf);
  78. }
  79. static void store_credential(const struct string_list *fns, struct credential *c)
  80. {
  81. struct string_list_item *fn;
  82. /*
  83. * Sanity check that what we are storing is actually sensible.
  84. * In particular, we can't make a URL without a protocol field.
  85. * Without either a host or pathname (depending on the scheme),
  86. * we have no primary key. And without a username and password,
  87. * we are not actually storing a credential.
  88. */
  89. if (!c->protocol || !(c->host || c->path) || !c->username || !c->password)
  90. return;
  91. for_each_string_list_item(fn, fns)
  92. if (!access(fn->string, F_OK)) {
  93. store_credential_file(fn->string, c);
  94. return;
  95. }
  96. /*
  97. * Write credential to the filename specified by fns->items[0], thus
  98. * creating it
  99. */
  100. if (fns->nr)
  101. store_credential_file(fns->items[0].string, c);
  102. }
  103. static void remove_credential(const struct string_list *fns, struct credential *c)
  104. {
  105. struct string_list_item *fn;
  106. /*
  107. * Sanity check that we actually have something to match
  108. * against. The input we get is a restrictive pattern,
  109. * so technically a blank credential means "erase everything".
  110. * But it is too easy to accidentally send this, since it is equivalent
  111. * to empty input. So explicitly disallow it, and require that the
  112. * pattern have some actual content to match.
  113. */
  114. if (!c->protocol && !c->host && !c->path && !c->username)
  115. return;
  116. for_each_string_list_item(fn, fns)
  117. if (!access(fn->string, F_OK))
  118. rewrite_credential_file(fn->string, c, NULL);
  119. }
  120. static void lookup_credential(const struct string_list *fns, struct credential *c)
  121. {
  122. struct string_list_item *fn;
  123. for_each_string_list_item(fn, fns)
  124. if (parse_credential_file(fn->string, c, print_entry, NULL))
  125. return; /* Found credential */
  126. }
  127. int cmd_main(int argc, const char **argv)
  128. {
  129. const char * const usage[] = {
  130. "git credential-store [<options>] <action>",
  131. NULL
  132. };
  133. const char *op;
  134. struct credential c = CREDENTIAL_INIT;
  135. struct string_list fns = STRING_LIST_INIT_DUP;
  136. char *file = NULL;
  137. struct option options[] = {
  138. OPT_STRING(0, "file", &file, "path",
  139. "fetch and store credentials in <path>"),
  140. OPT_END()
  141. };
  142. umask(077);
  143. argc = parse_options(argc, (const char **)argv, NULL, options, usage, 0);
  144. if (argc != 1)
  145. usage_with_options(usage, options);
  146. op = argv[0];
  147. if (file) {
  148. string_list_append(&fns, file);
  149. } else {
  150. if ((file = expand_user_path("~/.git-credentials", 0)))
  151. string_list_append_nodup(&fns, file);
  152. file = xdg_config_home("credentials");
  153. if (file)
  154. string_list_append_nodup(&fns, file);
  155. }
  156. if (!fns.nr)
  157. die("unable to set up default path; use --file");
  158. if (credential_read(&c, stdin) < 0)
  159. die("unable to read credential");
  160. if (!strcmp(op, "get"))
  161. lookup_credential(&fns, &c);
  162. else if (!strcmp(op, "erase"))
  163. remove_credential(&fns, &c);
  164. else if (!strcmp(op, "store"))
  165. store_credential(&fns, &c);
  166. else
  167. ; /* Ignore unknown operation. */
  168. string_list_clear(&fns, 0);
  169. return 0;
  170. }