2 #include "credential.h"
4 #include "string-list.h"
5 #include "run-command.h"
7 static struct string_list default_methods;
9 static int credential_config_callback(const char *var, const char *value,
12 struct credential *c = data;
17 var = skip_prefix(var, "credential.");
21 var = skip_prefix(var, c->unique);
29 if (!strcmp(var, "username")) {
31 c->username = xstrdup(value);
33 else if (!strcmp(var, "password")) {
35 c->password = xstrdup(value);
40 void credential_from_config(struct credential *c)
43 git_config(credential_config_callback, c);
46 static char *credential_ask_one(const char *what, const char *desc)
48 struct strbuf prompt = STRBUF_INIT;
52 strbuf_addf(&prompt, "%s for '%s': ", what, desc);
54 strbuf_addf(&prompt, "%s: ", what);
56 /* FIXME: for usernames, we should do something less magical that
57 * actually echoes the characters. However, we need to read from
58 * /dev/tty and not stdio, which is not portable (but getpass will do
59 * it for us). http.c uses the same workaround. */
60 r = git_getpass(prompt.buf);
62 strbuf_release(&prompt);
66 int credential_getpass(struct credential *c)
68 credential_from_config(c);
71 c->username = credential_ask_one("Username", c->description);
73 c->password = credential_ask_one("Password", c->description);
77 static int read_credential_response(struct credential *c, FILE *fp)
79 struct strbuf response = STRBUF_INIT;
81 while (strbuf_getline(&response, fp, '\n') != EOF) {
82 char *key = response.buf;
83 char *value = strchr(key, '=');
86 warning("bad output from credential helper: %s", key);
87 strbuf_release(&response);
92 if (!strcmp(key, "username")) {
94 c->username = xstrdup(value);
96 else if (!strcmp(key, "password")) {
98 c->password = xstrdup(value);
100 /* ignore other responses; we don't know what they mean */
103 strbuf_release(&response);
107 static int run_credential_helper(struct credential *c, const char *cmd)
109 struct child_process helper;
110 const char *argv[] = { NULL, NULL };
114 memset(&helper, 0, sizeof(helper));
117 helper.use_shell = 1;
121 if (start_command(&helper))
123 fp = xfdopen(helper.out, "r");
125 r = read_credential_response(c, fp);
128 if (finish_command(&helper))
134 static void add_item(struct strbuf *out, const char *key, const char *value)
138 strbuf_addf(out, " --%s=", key);
139 sq_quote_buf(out, value);
142 static int first_word_is_alnum(const char *s)
144 for (; *s && *s != ' '; s++)
150 static int credential_do(struct credential *c, const char *method,
153 struct strbuf cmd = STRBUF_INIT;
156 if (first_word_is_alnum(method))
157 strbuf_addf(&cmd, "git credential-%s", method);
159 strbuf_addstr(&cmd, method);
162 strbuf_addf(&cmd, " %s", extra);
164 add_item(&cmd, "description", c->description);
165 add_item(&cmd, "unique", c->unique);
166 add_item(&cmd, "username", c->username);
168 r = run_credential_helper(c, cmd.buf);
170 strbuf_release(&cmd);
174 void credential_fill(struct credential *c, const struct string_list *methods)
176 struct strbuf err = STRBUF_INIT;
179 methods = &default_methods;
181 if (!credential_fill_gently(c, methods))
184 strbuf_addstr(&err, "unable to get credentials");
186 strbuf_addf(&err, "for '%s'", c->description);
187 if (methods->nr == 1)
188 strbuf_addf(&err, "; tried '%s'", methods->items[0].string);
191 strbuf_addstr(&err, "; tried:");
192 for (i = 0; i < methods->nr; i++)
193 strbuf_addf(&err, "\n %s", methods->items[i].string);
198 int credential_fill_gently(struct credential *c,
199 const struct string_list *methods)
203 if (c->username && c->password)
207 methods = &default_methods;
210 return credential_getpass(c);
212 for (i = 0; i < methods->nr; i++) {
213 if (!credential_do(c, methods->items[i].string, NULL) &&
214 c->username && c->password)
221 void credential_reject(struct credential *c, const struct string_list *methods)
226 methods = &default_methods;
229 for (i = 0; i < methods->nr; i++) {
230 /* ignore errors, there's nothing we can do */
231 credential_do(c, methods->items[i].string, "--reject");
241 int git_default_credential_config(const char *var, const char *value)
243 if (!strcmp(var, "credential.helper")) {
245 return config_error_nonbool(var);
246 string_list_append(&default_methods, xstrdup(value));