1 /*
2 * Copyright (C) the libgit2 contributors. All rights reserved.
3 *
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
6 */
7
8 #include "common.h"
9
10 #include "git2/credential.h"
11 #include "git2/sys/credential.h"
12 #include "git2/credential_helpers.h"
13
14 static int git_credential_ssh_key_type_new(
15 git_credential **cred,
16 const char *username,
17 const char *publickey,
18 const char *privatekey,
19 const char *passphrase,
20 git_credential_t credtype);
21
git_credential_has_username(git_credential * cred)22 int git_credential_has_username(git_credential *cred)
23 {
24 if (cred->credtype == GIT_CREDENTIAL_DEFAULT)
25 return 0;
26
27 return 1;
28 }
29
git_credential_get_username(git_credential * cred)30 const char *git_credential_get_username(git_credential *cred)
31 {
32 switch (cred->credtype) {
33 case GIT_CREDENTIAL_USERNAME:
34 {
35 git_credential_username *c = (git_credential_username *) cred;
36 return c->username;
37 }
38 case GIT_CREDENTIAL_USERPASS_PLAINTEXT:
39 {
40 git_credential_userpass_plaintext *c = (git_credential_userpass_plaintext *) cred;
41 return c->username;
42 }
43 case GIT_CREDENTIAL_SSH_KEY:
44 case GIT_CREDENTIAL_SSH_MEMORY:
45 {
46 git_credential_ssh_key *c = (git_credential_ssh_key *) cred;
47 return c->username;
48 }
49 case GIT_CREDENTIAL_SSH_CUSTOM:
50 {
51 git_credential_ssh_custom *c = (git_credential_ssh_custom *) cred;
52 return c->username;
53 }
54 case GIT_CREDENTIAL_SSH_INTERACTIVE:
55 {
56 git_credential_ssh_interactive *c = (git_credential_ssh_interactive *) cred;
57 return c->username;
58 }
59
60 default:
61 return NULL;
62 }
63 }
64
plaintext_free(struct git_credential * cred)65 static void plaintext_free(struct git_credential *cred)
66 {
67 git_credential_userpass_plaintext *c = (git_credential_userpass_plaintext *)cred;
68
69 git__free(c->username);
70
71 /* Zero the memory which previously held the password */
72 if (c->password) {
73 size_t pass_len = strlen(c->password);
74 git__memzero(c->password, pass_len);
75 git__free(c->password);
76 }
77
78 git__free(c);
79 }
80
git_credential_userpass_plaintext_new(git_credential ** cred,const char * username,const char * password)81 int git_credential_userpass_plaintext_new(
82 git_credential **cred,
83 const char *username,
84 const char *password)
85 {
86 git_credential_userpass_plaintext *c;
87
88 GIT_ASSERT_ARG(cred);
89 GIT_ASSERT_ARG(username);
90 GIT_ASSERT_ARG(password);
91
92 c = git__malloc(sizeof(git_credential_userpass_plaintext));
93 GIT_ERROR_CHECK_ALLOC(c);
94
95 c->parent.credtype = GIT_CREDENTIAL_USERPASS_PLAINTEXT;
96 c->parent.free = plaintext_free;
97 c->username = git__strdup(username);
98
99 if (!c->username) {
100 git__free(c);
101 return -1;
102 }
103
104 c->password = git__strdup(password);
105
106 if (!c->password) {
107 git__free(c->username);
108 git__free(c);
109 return -1;
110 }
111
112 *cred = &c->parent;
113 return 0;
114 }
115
ssh_key_free(struct git_credential * cred)116 static void ssh_key_free(struct git_credential *cred)
117 {
118 git_credential_ssh_key *c =
119 (git_credential_ssh_key *)cred;
120
121 git__free(c->username);
122
123 if (c->privatekey) {
124 /* Zero the memory which previously held the private key */
125 size_t key_len = strlen(c->privatekey);
126 git__memzero(c->privatekey, key_len);
127 git__free(c->privatekey);
128 }
129
130 if (c->passphrase) {
131 /* Zero the memory which previously held the passphrase */
132 size_t pass_len = strlen(c->passphrase);
133 git__memzero(c->passphrase, pass_len);
134 git__free(c->passphrase);
135 }
136
137 if (c->publickey) {
138 /* Zero the memory which previously held the public key */
139 size_t key_len = strlen(c->publickey);
140 git__memzero(c->publickey, key_len);
141 git__free(c->publickey);
142 }
143
144 git__free(c);
145 }
146
ssh_interactive_free(struct git_credential * cred)147 static void ssh_interactive_free(struct git_credential *cred)
148 {
149 git_credential_ssh_interactive *c = (git_credential_ssh_interactive *)cred;
150
151 git__free(c->username);
152
153 git__free(c);
154 }
155
ssh_custom_free(struct git_credential * cred)156 static void ssh_custom_free(struct git_credential *cred)
157 {
158 git_credential_ssh_custom *c = (git_credential_ssh_custom *)cred;
159
160 git__free(c->username);
161
162 if (c->publickey) {
163 /* Zero the memory which previously held the publickey */
164 size_t key_len = strlen(c->publickey);
165 git__memzero(c->publickey, key_len);
166 git__free(c->publickey);
167 }
168
169 git__free(c);
170 }
171
default_free(struct git_credential * cred)172 static void default_free(struct git_credential *cred)
173 {
174 git_credential_default *c = (git_credential_default *)cred;
175
176 git__free(c);
177 }
178
username_free(struct git_credential * cred)179 static void username_free(struct git_credential *cred)
180 {
181 git__free(cred);
182 }
183
git_credential_ssh_key_new(git_credential ** cred,const char * username,const char * publickey,const char * privatekey,const char * passphrase)184 int git_credential_ssh_key_new(
185 git_credential **cred,
186 const char *username,
187 const char *publickey,
188 const char *privatekey,
189 const char *passphrase)
190 {
191 return git_credential_ssh_key_type_new(
192 cred,
193 username,
194 publickey,
195 privatekey,
196 passphrase,
197 GIT_CREDENTIAL_SSH_KEY);
198 }
199
git_credential_ssh_key_memory_new(git_credential ** cred,const char * username,const char * publickey,const char * privatekey,const char * passphrase)200 int git_credential_ssh_key_memory_new(
201 git_credential **cred,
202 const char *username,
203 const char *publickey,
204 const char *privatekey,
205 const char *passphrase)
206 {
207 #ifdef GIT_SSH_MEMORY_CREDENTIALS
208 return git_credential_ssh_key_type_new(
209 cred,
210 username,
211 publickey,
212 privatekey,
213 passphrase,
214 GIT_CREDENTIAL_SSH_MEMORY);
215 #else
216 GIT_UNUSED(cred);
217 GIT_UNUSED(username);
218 GIT_UNUSED(publickey);
219 GIT_UNUSED(privatekey);
220 GIT_UNUSED(passphrase);
221
222 git_error_set(GIT_ERROR_INVALID,
223 "this version of libgit2 was not built with ssh memory credentials.");
224 return -1;
225 #endif
226 }
227
git_credential_ssh_key_type_new(git_credential ** cred,const char * username,const char * publickey,const char * privatekey,const char * passphrase,git_credential_t credtype)228 static int git_credential_ssh_key_type_new(
229 git_credential **cred,
230 const char *username,
231 const char *publickey,
232 const char *privatekey,
233 const char *passphrase,
234 git_credential_t credtype)
235 {
236 git_credential_ssh_key *c;
237
238 GIT_ASSERT_ARG(username);
239 GIT_ASSERT_ARG(cred);
240 GIT_ASSERT_ARG(privatekey);
241
242 c = git__calloc(1, sizeof(git_credential_ssh_key));
243 GIT_ERROR_CHECK_ALLOC(c);
244
245 c->parent.credtype = credtype;
246 c->parent.free = ssh_key_free;
247
248 c->username = git__strdup(username);
249 GIT_ERROR_CHECK_ALLOC(c->username);
250
251 c->privatekey = git__strdup(privatekey);
252 GIT_ERROR_CHECK_ALLOC(c->privatekey);
253
254 if (publickey) {
255 c->publickey = git__strdup(publickey);
256 GIT_ERROR_CHECK_ALLOC(c->publickey);
257 }
258
259 if (passphrase) {
260 c->passphrase = git__strdup(passphrase);
261 GIT_ERROR_CHECK_ALLOC(c->passphrase);
262 }
263
264 *cred = &c->parent;
265 return 0;
266 }
267
git_credential_ssh_interactive_new(git_credential ** out,const char * username,git_credential_ssh_interactive_cb prompt_callback,void * payload)268 int git_credential_ssh_interactive_new(
269 git_credential **out,
270 const char *username,
271 git_credential_ssh_interactive_cb prompt_callback,
272 void *payload)
273 {
274 git_credential_ssh_interactive *c;
275
276 GIT_ASSERT_ARG(out);
277 GIT_ASSERT_ARG(username);
278 GIT_ASSERT_ARG(prompt_callback);
279
280 c = git__calloc(1, sizeof(git_credential_ssh_interactive));
281 GIT_ERROR_CHECK_ALLOC(c);
282
283 c->parent.credtype = GIT_CREDENTIAL_SSH_INTERACTIVE;
284 c->parent.free = ssh_interactive_free;
285
286 c->username = git__strdup(username);
287 GIT_ERROR_CHECK_ALLOC(c->username);
288
289 c->prompt_callback = prompt_callback;
290 c->payload = payload;
291
292 *out = &c->parent;
293 return 0;
294 }
295
git_credential_ssh_key_from_agent(git_credential ** cred,const char * username)296 int git_credential_ssh_key_from_agent(git_credential **cred, const char *username) {
297 git_credential_ssh_key *c;
298
299 GIT_ASSERT_ARG(username);
300 GIT_ASSERT_ARG(cred);
301
302 c = git__calloc(1, sizeof(git_credential_ssh_key));
303 GIT_ERROR_CHECK_ALLOC(c);
304
305 c->parent.credtype = GIT_CREDENTIAL_SSH_KEY;
306 c->parent.free = ssh_key_free;
307
308 c->username = git__strdup(username);
309 GIT_ERROR_CHECK_ALLOC(c->username);
310
311 c->privatekey = NULL;
312
313 *cred = &c->parent;
314 return 0;
315 }
316
git_credential_ssh_custom_new(git_credential ** cred,const char * username,const char * publickey,size_t publickey_len,git_credential_sign_cb sign_callback,void * payload)317 int git_credential_ssh_custom_new(
318 git_credential **cred,
319 const char *username,
320 const char *publickey,
321 size_t publickey_len,
322 git_credential_sign_cb sign_callback,
323 void *payload)
324 {
325 git_credential_ssh_custom *c;
326
327 GIT_ASSERT_ARG(username);
328 GIT_ASSERT_ARG(cred);
329
330 c = git__calloc(1, sizeof(git_credential_ssh_custom));
331 GIT_ERROR_CHECK_ALLOC(c);
332
333 c->parent.credtype = GIT_CREDENTIAL_SSH_CUSTOM;
334 c->parent.free = ssh_custom_free;
335
336 c->username = git__strdup(username);
337 GIT_ERROR_CHECK_ALLOC(c->username);
338
339 if (publickey_len > 0) {
340 c->publickey = git__malloc(publickey_len);
341 GIT_ERROR_CHECK_ALLOC(c->publickey);
342
343 memcpy(c->publickey, publickey, publickey_len);
344 }
345
346 c->publickey_len = publickey_len;
347 c->sign_callback = sign_callback;
348 c->payload = payload;
349
350 *cred = &c->parent;
351 return 0;
352 }
353
git_credential_default_new(git_credential ** cred)354 int git_credential_default_new(git_credential **cred)
355 {
356 git_credential_default *c;
357
358 GIT_ASSERT_ARG(cred);
359
360 c = git__calloc(1, sizeof(git_credential_default));
361 GIT_ERROR_CHECK_ALLOC(c);
362
363 c->credtype = GIT_CREDENTIAL_DEFAULT;
364 c->free = default_free;
365
366 *cred = c;
367 return 0;
368 }
369
git_credential_username_new(git_credential ** cred,const char * username)370 int git_credential_username_new(git_credential **cred, const char *username)
371 {
372 git_credential_username *c;
373 size_t len, allocsize;
374
375 GIT_ASSERT_ARG(cred);
376
377 len = strlen(username);
378
379 GIT_ERROR_CHECK_ALLOC_ADD(&allocsize, sizeof(git_credential_username), len);
380 GIT_ERROR_CHECK_ALLOC_ADD(&allocsize, allocsize, 1);
381 c = git__malloc(allocsize);
382 GIT_ERROR_CHECK_ALLOC(c);
383
384 c->parent.credtype = GIT_CREDENTIAL_USERNAME;
385 c->parent.free = username_free;
386 memcpy(c->username, username, len + 1);
387
388 *cred = (git_credential *) c;
389 return 0;
390 }
391
git_credential_free(git_credential * cred)392 void git_credential_free(git_credential *cred)
393 {
394 if (!cred)
395 return;
396
397 cred->free(cred);
398 }
399
400 /* Deprecated credential functions */
401
402 #ifndef GIT_DEPRECATE_HARD
git_cred_has_username(git_credential * cred)403 int git_cred_has_username(git_credential *cred)
404 {
405 return git_credential_has_username(cred);
406 }
407
git_cred_get_username(git_credential * cred)408 const char *git_cred_get_username(git_credential *cred)
409 {
410 return git_credential_get_username(cred);
411 }
412
git_cred_userpass_plaintext_new(git_credential ** out,const char * username,const char * password)413 int git_cred_userpass_plaintext_new(
414 git_credential **out,
415 const char *username,
416 const char *password)
417 {
418 return git_credential_userpass_plaintext_new(out,username, password);
419 }
420
git_cred_default_new(git_credential ** out)421 int git_cred_default_new(git_credential **out)
422 {
423 return git_credential_default_new(out);
424 }
425
git_cred_username_new(git_credential ** out,const char * username)426 int git_cred_username_new(git_credential **out, const char *username)
427 {
428 return git_credential_username_new(out, username);
429 }
430
git_cred_ssh_key_new(git_credential ** out,const char * username,const char * publickey,const char * privatekey,const char * passphrase)431 int git_cred_ssh_key_new(
432 git_credential **out,
433 const char *username,
434 const char *publickey,
435 const char *privatekey,
436 const char *passphrase)
437 {
438 return git_credential_ssh_key_new(out, username,
439 publickey, privatekey, passphrase);
440 }
441
git_cred_ssh_key_memory_new(git_credential ** out,const char * username,const char * publickey,const char * privatekey,const char * passphrase)442 int git_cred_ssh_key_memory_new(
443 git_credential **out,
444 const char *username,
445 const char *publickey,
446 const char *privatekey,
447 const char *passphrase)
448 {
449 return git_credential_ssh_key_memory_new(out, username,
450 publickey, privatekey, passphrase);
451 }
452
git_cred_ssh_interactive_new(git_credential ** out,const char * username,git_credential_ssh_interactive_cb prompt_callback,void * payload)453 int git_cred_ssh_interactive_new(
454 git_credential **out,
455 const char *username,
456 git_credential_ssh_interactive_cb prompt_callback,
457 void *payload)
458 {
459 return git_credential_ssh_interactive_new(out, username,
460 prompt_callback, payload);
461 }
462
git_cred_ssh_key_from_agent(git_credential ** out,const char * username)463 int git_cred_ssh_key_from_agent(
464 git_credential **out,
465 const char *username)
466 {
467 return git_credential_ssh_key_from_agent(out, username);
468 }
469
git_cred_ssh_custom_new(git_credential ** out,const char * username,const char * publickey,size_t publickey_len,git_credential_sign_cb sign_callback,void * payload)470 int git_cred_ssh_custom_new(
471 git_credential **out,
472 const char *username,
473 const char *publickey,
474 size_t publickey_len,
475 git_credential_sign_cb sign_callback,
476 void *payload)
477 {
478 return git_credential_ssh_custom_new(out, username,
479 publickey, publickey_len, sign_callback, payload);
480 }
481
git_cred_free(git_credential * cred)482 void git_cred_free(git_credential *cred)
483 {
484 git_credential_free(cred);
485 }
486 #endif
487