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 "cred.h"
9 
10 #include "git2.h"
11 #include "smart.h"
12 #include "git2/cred_helpers.h"
13 
14 static int git_cred_ssh_key_type_new(
15 	git_cred **cred,
16 	const char *username,
17 	const char *publickey,
18 	const char *privatekey,
19 	const char *passphrase,
20 	git_credtype_t credtype);
21 
git_cred_has_username(git_cred * cred)22 int git_cred_has_username(git_cred *cred)
23 {
24 	if (cred->credtype == GIT_CREDTYPE_DEFAULT)
25 		return 0;
26 
27 	return 1;
28 }
29 
git_cred__username(git_cred * cred)30 const char *git_cred__username(git_cred *cred)
31 {
32 	switch (cred->credtype) {
33 	case GIT_CREDTYPE_USERNAME:
34 	{
35 		git_cred_username *c = (git_cred_username *) cred;
36 		return c->username;
37 	}
38 	case GIT_CREDTYPE_USERPASS_PLAINTEXT:
39 	{
40 		git_cred_userpass_plaintext *c = (git_cred_userpass_plaintext *) cred;
41 		return c->username;
42 	}
43 	case GIT_CREDTYPE_SSH_KEY:
44 	case GIT_CREDTYPE_SSH_MEMORY:
45 	{
46 		git_cred_ssh_key *c = (git_cred_ssh_key *) cred;
47 		return c->username;
48 	}
49 	case GIT_CREDTYPE_SSH_CUSTOM:
50 	{
51 		git_cred_ssh_custom *c = (git_cred_ssh_custom *) cred;
52 		return c->username;
53 	}
54 	case GIT_CREDTYPE_SSH_INTERACTIVE:
55 	{
56 		git_cred_ssh_interactive *c = (git_cred_ssh_interactive *) cred;
57 		return c->username;
58 	}
59 
60 	default:
61 		return NULL;
62 	}
63 }
64 
plaintext_free(struct git_cred * cred)65 static void plaintext_free(struct git_cred *cred)
66 {
67 	git_cred_userpass_plaintext *c = (git_cred_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_cred_userpass_plaintext_new(git_cred ** cred,const char * username,const char * password)81 int git_cred_userpass_plaintext_new(
82 	git_cred **cred,
83 	const char *username,
84 	const char *password)
85 {
86 	git_cred_userpass_plaintext *c;
87 
88 	assert(cred && username && password);
89 
90 	c = git__malloc(sizeof(git_cred_userpass_plaintext));
91 	GIT_ERROR_CHECK_ALLOC(c);
92 
93 	c->parent.credtype = GIT_CREDTYPE_USERPASS_PLAINTEXT;
94 	c->parent.free = plaintext_free;
95 	c->username = git__strdup(username);
96 
97 	if (!c->username) {
98 		git__free(c);
99 		return -1;
100 	}
101 
102 	c->password = git__strdup(password);
103 
104 	if (!c->password) {
105 		git__free(c->username);
106 		git__free(c);
107 		return -1;
108 	}
109 
110 	*cred = &c->parent;
111 	return 0;
112 }
113 
ssh_key_free(struct git_cred * cred)114 static void ssh_key_free(struct git_cred *cred)
115 {
116 	git_cred_ssh_key *c =
117 		(git_cred_ssh_key *)cred;
118 
119 	git__free(c->username);
120 
121 	if (c->privatekey) {
122 		/* Zero the memory which previously held the private key */
123 		size_t key_len = strlen(c->privatekey);
124 		git__memzero(c->privatekey, key_len);
125 		git__free(c->privatekey);
126 	}
127 
128 	if (c->passphrase) {
129 		/* Zero the memory which previously held the passphrase */
130 		size_t pass_len = strlen(c->passphrase);
131 		git__memzero(c->passphrase, pass_len);
132 		git__free(c->passphrase);
133 	}
134 
135 	if (c->publickey) {
136 		/* Zero the memory which previously held the public key */
137 		size_t key_len = strlen(c->publickey);
138 		git__memzero(c->publickey, key_len);
139 		git__free(c->publickey);
140 	}
141 
142 	git__free(c);
143 }
144 
ssh_interactive_free(struct git_cred * cred)145 static void ssh_interactive_free(struct git_cred *cred)
146 {
147 	git_cred_ssh_interactive *c = (git_cred_ssh_interactive *)cred;
148 
149 	git__free(c->username);
150 
151 	git__free(c);
152 }
153 
ssh_custom_free(struct git_cred * cred)154 static void ssh_custom_free(struct git_cred *cred)
155 {
156 	git_cred_ssh_custom *c = (git_cred_ssh_custom *)cred;
157 
158 	git__free(c->username);
159 
160 	if (c->publickey) {
161 		/* Zero the memory which previously held the publickey */
162 		size_t key_len = strlen(c->publickey);
163 		git__memzero(c->publickey, key_len);
164 		git__free(c->publickey);
165 	}
166 
167 	git__free(c);
168 }
169 
default_free(struct git_cred * cred)170 static void default_free(struct git_cred *cred)
171 {
172 	git_cred_default *c = (git_cred_default *)cred;
173 
174 	git__free(c);
175 }
176 
username_free(struct git_cred * cred)177 static void username_free(struct git_cred *cred)
178 {
179 	git__free(cred);
180 }
181 
git_cred_ssh_key_new(git_cred ** cred,const char * username,const char * publickey,const char * privatekey,const char * passphrase)182 int git_cred_ssh_key_new(
183 	git_cred **cred,
184 	const char *username,
185 	const char *publickey,
186 	const char *privatekey,
187 	const char *passphrase)
188 {
189 	return git_cred_ssh_key_type_new(
190 		cred,
191 		username,
192 		publickey,
193 		privatekey,
194 		passphrase,
195 		GIT_CREDTYPE_SSH_KEY);
196 }
197 
git_cred_ssh_key_memory_new(git_cred ** cred,const char * username,const char * publickey,const char * privatekey,const char * passphrase)198 int git_cred_ssh_key_memory_new(
199 	git_cred **cred,
200 	const char *username,
201 	const char *publickey,
202 	const char *privatekey,
203 	const char *passphrase)
204 {
205 #ifdef GIT_SSH_MEMORY_CREDENTIALS
206 	return git_cred_ssh_key_type_new(
207 		cred,
208 		username,
209 		publickey,
210 		privatekey,
211 		passphrase,
212 		GIT_CREDTYPE_SSH_MEMORY);
213 #else
214 	GIT_UNUSED(cred);
215 	GIT_UNUSED(username);
216 	GIT_UNUSED(publickey);
217 	GIT_UNUSED(privatekey);
218 	GIT_UNUSED(passphrase);
219 
220 	git_error_set(GIT_ERROR_INVALID,
221 		"this version of libgit2 was not built with ssh memory credentials.");
222 	return -1;
223 #endif
224 }
225 
git_cred_ssh_key_type_new(git_cred ** cred,const char * username,const char * publickey,const char * privatekey,const char * passphrase,git_credtype_t credtype)226 static int git_cred_ssh_key_type_new(
227 	git_cred **cred,
228 	const char *username,
229 	const char *publickey,
230 	const char *privatekey,
231 	const char *passphrase,
232 	git_credtype_t credtype)
233 {
234 	git_cred_ssh_key *c;
235 
236 	assert(username && cred && privatekey);
237 
238 	c = git__calloc(1, sizeof(git_cred_ssh_key));
239 	GIT_ERROR_CHECK_ALLOC(c);
240 
241 	c->parent.credtype = credtype;
242 	c->parent.free = ssh_key_free;
243 
244 	c->username = git__strdup(username);
245 	GIT_ERROR_CHECK_ALLOC(c->username);
246 
247 	c->privatekey = git__strdup(privatekey);
248 	GIT_ERROR_CHECK_ALLOC(c->privatekey);
249 
250 	if (publickey) {
251 		c->publickey = git__strdup(publickey);
252 		GIT_ERROR_CHECK_ALLOC(c->publickey);
253 	}
254 
255 	if (passphrase) {
256 		c->passphrase = git__strdup(passphrase);
257 		GIT_ERROR_CHECK_ALLOC(c->passphrase);
258 	}
259 
260 	*cred = &c->parent;
261 	return 0;
262 }
263 
git_cred_ssh_interactive_new(git_cred ** out,const char * username,git_cred_ssh_interactive_callback prompt_callback,void * payload)264 int git_cred_ssh_interactive_new(
265 	git_cred **out,
266 	const char *username,
267 	git_cred_ssh_interactive_callback prompt_callback,
268 	void *payload)
269 {
270 	git_cred_ssh_interactive *c;
271 
272 	assert(out && username && prompt_callback);
273 
274 	c = git__calloc(1, sizeof(git_cred_ssh_interactive));
275 	GIT_ERROR_CHECK_ALLOC(c);
276 
277 	c->parent.credtype = GIT_CREDTYPE_SSH_INTERACTIVE;
278 	c->parent.free = ssh_interactive_free;
279 
280 	c->username = git__strdup(username);
281 	GIT_ERROR_CHECK_ALLOC(c->username);
282 
283 	c->prompt_callback = prompt_callback;
284 	c->payload = payload;
285 
286 	*out = &c->parent;
287 	return 0;
288 }
289 
git_cred_ssh_key_from_agent(git_cred ** cred,const char * username)290 int git_cred_ssh_key_from_agent(git_cred **cred, const char *username) {
291 	git_cred_ssh_key *c;
292 
293 	assert(username && cred);
294 
295 	c = git__calloc(1, sizeof(git_cred_ssh_key));
296 	GIT_ERROR_CHECK_ALLOC(c);
297 
298 	c->parent.credtype = GIT_CREDTYPE_SSH_KEY;
299 	c->parent.free = ssh_key_free;
300 
301 	c->username = git__strdup(username);
302 	GIT_ERROR_CHECK_ALLOC(c->username);
303 
304 	c->privatekey = NULL;
305 
306 	*cred = &c->parent;
307 	return 0;
308 }
309 
git_cred_ssh_custom_new(git_cred ** cred,const char * username,const char * publickey,size_t publickey_len,git_cred_sign_callback sign_callback,void * payload)310 int git_cred_ssh_custom_new(
311 	git_cred **cred,
312 	const char *username,
313 	const char *publickey,
314 	size_t publickey_len,
315 	git_cred_sign_callback sign_callback,
316 	void *payload)
317 {
318 	git_cred_ssh_custom *c;
319 
320 	assert(username && cred);
321 
322 	c = git__calloc(1, sizeof(git_cred_ssh_custom));
323 	GIT_ERROR_CHECK_ALLOC(c);
324 
325 	c->parent.credtype = GIT_CREDTYPE_SSH_CUSTOM;
326 	c->parent.free = ssh_custom_free;
327 
328 	c->username = git__strdup(username);
329 	GIT_ERROR_CHECK_ALLOC(c->username);
330 
331 	if (publickey_len > 0) {
332 		c->publickey = git__malloc(publickey_len);
333 		GIT_ERROR_CHECK_ALLOC(c->publickey);
334 
335 		memcpy(c->publickey, publickey, publickey_len);
336 	}
337 
338 	c->publickey_len = publickey_len;
339 	c->sign_callback = sign_callback;
340 	c->payload = payload;
341 
342 	*cred = &c->parent;
343 	return 0;
344 }
345 
git_cred_default_new(git_cred ** cred)346 int git_cred_default_new(git_cred **cred)
347 {
348 	git_cred_default *c;
349 
350 	assert(cred);
351 
352 	c = git__calloc(1, sizeof(git_cred_default));
353 	GIT_ERROR_CHECK_ALLOC(c);
354 
355 	c->credtype = GIT_CREDTYPE_DEFAULT;
356 	c->free = default_free;
357 
358 	*cred = c;
359 	return 0;
360 }
361 
git_cred_username_new(git_cred ** cred,const char * username)362 int git_cred_username_new(git_cred **cred, const char *username)
363 {
364 	git_cred_username *c;
365 	size_t len, allocsize;
366 
367 	assert(cred);
368 
369 	len = strlen(username);
370 
371 	GIT_ERROR_CHECK_ALLOC_ADD(&allocsize, sizeof(git_cred_username), len);
372 	GIT_ERROR_CHECK_ALLOC_ADD(&allocsize, allocsize, 1);
373 	c = git__malloc(allocsize);
374 	GIT_ERROR_CHECK_ALLOC(c);
375 
376 	c->parent.credtype = GIT_CREDTYPE_USERNAME;
377 	c->parent.free = username_free;
378 	memcpy(c->username, username, len + 1);
379 
380 	*cred = (git_cred *) c;
381 	return 0;
382 }
383 
git_cred_free(git_cred * cred)384 void git_cred_free(git_cred *cred)
385 {
386 	if (!cred)
387 		return;
388 
389 	cred->free(cred);
390 }
391