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.
 
 
 
 
 
 

195 lines
5.0 KiB

  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, 1);
  66. strbuf_addch(&buf, ':');
  67. strbuf_addstr_urlencode(&buf, c->password, 1);
  68. strbuf_addch(&buf, '@');
  69. if (c->host)
  70. strbuf_addstr_urlencode(&buf, c->host, 1);
  71. if (c->path) {
  72. strbuf_addch(&buf, '/');
  73. strbuf_addstr_urlencode(&buf, c->path, 0);
  74. }
  75. rewrite_credential_file(fn, c, &buf);
  76. strbuf_release(&buf);
  77. }
  78. static void store_credential(const struct string_list *fns, struct credential *c)
  79. {
  80. struct string_list_item *fn;
  81. /*
  82. * Sanity check that what we are storing is actually sensible.
  83. * In particular, we can't make a URL without a protocol field.
  84. * Without either a host or pathname (depending on the scheme),
  85. * we have no primary key. And without a username and password,
  86. * we are not actually storing a credential.
  87. */
  88. if (!c->protocol || !(c->host || c->path) || !c->username || !c->password)
  89. return;
  90. for_each_string_list_item(fn, fns)
  91. if (!access(fn->string, F_OK)) {
  92. store_credential_file(fn->string, c);
  93. return;
  94. }
  95. /*
  96. * Write credential to the filename specified by fns->items[0], thus
  97. * creating it
  98. */
  99. if (fns->nr)
  100. store_credential_file(fns->items[0].string, c);
  101. }
  102. static void remove_credential(const struct string_list *fns, struct credential *c)
  103. {
  104. struct string_list_item *fn;
  105. /*
  106. * Sanity check that we actually have something to match
  107. * against. The input we get is a restrictive pattern,
  108. * so technically a blank credential means "erase everything".
  109. * But it is too easy to accidentally send this, since it is equivalent
  110. * to empty input. So explicitly disallow it, and require that the
  111. * pattern have some actual content to match.
  112. */
  113. if (!c->protocol && !c->host && !c->path && !c->username)
  114. return;
  115. for_each_string_list_item(fn, fns)
  116. if (!access(fn->string, F_OK))
  117. rewrite_credential_file(fn->string, c, NULL);
  118. }
  119. static void lookup_credential(const struct string_list *fns, struct credential *c)
  120. {
  121. struct string_list_item *fn;
  122. for_each_string_list_item(fn, fns)
  123. if (parse_credential_file(fn->string, c, print_entry, NULL))
  124. return; /* Found credential */
  125. }
  126. int cmd_main(int argc, const char **argv)
  127. {
  128. const char * const usage[] = {
  129. "git credential-store [<options>] <action>",
  130. NULL
  131. };
  132. const char *op;
  133. struct credential c = CREDENTIAL_INIT;
  134. struct string_list fns = STRING_LIST_INIT_DUP;
  135. char *file = NULL;
  136. struct option options[] = {
  137. OPT_STRING(0, "file", &file, "path",
  138. "fetch and store credentials in <path>"),
  139. OPT_END()
  140. };
  141. umask(077);
  142. argc = parse_options(argc, (const char **)argv, NULL, options, usage, 0);
  143. if (argc != 1)
  144. usage_with_options(usage, options);
  145. op = argv[0];
  146. if (file) {
  147. string_list_append(&fns, file);
  148. } else {
  149. if ((file = expand_user_path("~/.git-credentials", 0)))
  150. string_list_append_nodup(&fns, file);
  151. file = xdg_config_home("credentials");
  152. if (file)
  153. string_list_append_nodup(&fns, file);
  154. }
  155. if (!fns.nr)
  156. die("unable to set up default path; use --file");
  157. if (credential_read(&c, stdin) < 0)
  158. die("unable to read credential");
  159. if (!strcmp(op, "get"))
  160. lookup_credential(&fns, &c);
  161. else if (!strcmp(op, "erase"))
  162. remove_credential(&fns, &c);
  163. else if (!strcmp(op, "store"))
  164. store_credential(&fns, &c);
  165. else
  166. ; /* Ignore unknown operation. */
  167. string_list_clear(&fns, 0);
  168. return 0;
  169. }