2 #include "credential.h"
3 #include "string-list.h"
4 #include "run-command.h"
6 void credential_init(struct credential
*c
)
8 memset(c
, 0, sizeof(*c
));
9 c
->helpers
.strdup_strings
= 1;
12 void credential_clear(struct credential
*c
)
19 string_list_clear(&c
->helpers
, 0);
24 static void credential_describe(struct credential
*c
, struct strbuf
*out
)
28 strbuf_addf(out
, "%s://", c
->protocol
);
29 if (c
->username
&& *c
->username
)
30 strbuf_addf(out
, "%s@", c
->username
);
32 strbuf_addstr(out
, c
->host
);
34 strbuf_addf(out
, "/%s", c
->path
);
37 static char *credential_ask_one(const char *what
, struct credential
*c
)
39 struct strbuf desc
= STRBUF_INIT
;
40 struct strbuf prompt
= STRBUF_INIT
;
43 credential_describe(c
, &desc
);
45 strbuf_addf(&prompt
, "%s for '%s': ", what
, desc
.buf
);
47 strbuf_addf(&prompt
, "%s: ", what
);
49 /* FIXME: for usernames, we should do something less magical that
50 * actually echoes the characters. However, we need to read from
51 * /dev/tty and not stdio, which is not portable (but getpass will do
52 * it for us). http.c uses the same workaround. */
53 r
= git_getpass(prompt
.buf
);
55 strbuf_release(&desc
);
56 strbuf_release(&prompt
);
60 static void credential_getpass(struct credential
*c
)
63 c
->username
= credential_ask_one("Username", c
);
65 c
->password
= credential_ask_one("Password", c
);
68 int credential_read(struct credential
*c
, FILE *fp
)
70 struct strbuf line
= STRBUF_INIT
;
72 while (strbuf_getline(&line
, fp
, '\n') != EOF
) {
74 char *value
= strchr(key
, '=');
80 warning("invalid credential line: %s", key
);
81 strbuf_release(&line
);
86 if (!strcmp(key
, "username")) {
88 c
->username
= xstrdup(value
);
89 } else if (!strcmp(key
, "password")) {
91 c
->password
= xstrdup(value
);
92 } else if (!strcmp(key
, "protocol")) {
94 c
->protocol
= xstrdup(value
);
95 } else if (!strcmp(key
, "host")) {
97 c
->host
= xstrdup(value
);
98 } else if (!strcmp(key
, "path")) {
100 c
->path
= xstrdup(value
);
103 * Ignore other lines; we don't know what they mean, but
104 * this future-proofs us when later versions of git do
105 * learn new lines, and the helpers are updated to match.
109 strbuf_release(&line
);
113 static void credential_write_item(FILE *fp
, const char *key
, const char *value
)
117 fprintf(fp
, "%s=%s\n", key
, value
);
120 static void credential_write(const struct credential
*c
, FILE *fp
)
122 credential_write_item(fp
, "protocol", c
->protocol
);
123 credential_write_item(fp
, "host", c
->host
);
124 credential_write_item(fp
, "path", c
->path
);
125 credential_write_item(fp
, "username", c
->username
);
126 credential_write_item(fp
, "password", c
->password
);
129 static int run_credential_helper(struct credential
*c
,
133 struct child_process helper
;
134 const char *argv
[] = { NULL
, NULL
};
137 memset(&helper
, 0, sizeof(helper
));
140 helper
.use_shell
= 1;
145 helper
.no_stdout
= 1;
147 if (start_command(&helper
) < 0)
150 fp
= xfdopen(helper
.in
, "w");
151 credential_write(c
, fp
);
156 fp
= xfdopen(helper
.out
, "r");
157 r
= credential_read(c
, fp
);
160 finish_command(&helper
);
165 if (finish_command(&helper
))
170 static int credential_do(struct credential
*c
, const char *helper
,
171 const char *operation
)
173 struct strbuf cmd
= STRBUF_INIT
;
176 if (helper
[0] == '!')
177 strbuf_addstr(&cmd
, helper
+ 1);
178 else if (is_absolute_path(helper
))
179 strbuf_addstr(&cmd
, helper
);
181 strbuf_addf(&cmd
, "git credential-%s", helper
);
183 strbuf_addf(&cmd
, " %s", operation
);
184 r
= run_credential_helper(c
, cmd
.buf
, !strcmp(operation
, "get"));
186 strbuf_release(&cmd
);
190 void credential_fill(struct credential
*c
)
194 if (c
->username
&& c
->password
)
197 for (i
= 0; i
< c
->helpers
.nr
; i
++) {
198 credential_do(c
, c
->helpers
.items
[i
].string
, "get");
199 if (c
->username
&& c
->password
)
203 credential_getpass(c
);
204 if (!c
->username
&& !c
->password
)
205 die("unable to get password from user");
208 void credential_approve(struct credential
*c
)
214 if (!c
->username
|| !c
->password
)
217 for (i
= 0; i
< c
->helpers
.nr
; i
++)
218 credential_do(c
, c
->helpers
.items
[i
].string
, "store");
222 void credential_reject(struct credential
*c
)
226 for (i
= 0; i
< c
->helpers
.nr
; i
++)
227 credential_do(c
, c
->helpers
.items
[i
].string
, "erase");