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
));