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