Line data Source code
1 : /*
2 : SSSD - auth utils
3 :
4 : Copyright (C) Simo Sorce <simo@redhat.com> 2012
5 :
6 : This program is free software; you can redistribute it and/or modify
7 : it under the terms of the GNU General Public License as published by
8 : the Free Software Foundation; either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program. If not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include "authtok.h"
21 :
22 : struct sss_auth_token {
23 : enum sss_authtok_type type;
24 : uint8_t *data;
25 : size_t length;
26 : };
27 :
28 50 : enum sss_authtok_type sss_authtok_get_type(struct sss_auth_token *tok)
29 : {
30 50 : return tok->type;
31 : }
32 :
33 11 : size_t sss_authtok_get_size(struct sss_auth_token *tok)
34 : {
35 11 : if (!tok) {
36 0 : return 0;
37 : }
38 11 : switch (tok->type) {
39 : case SSS_AUTHTOK_TYPE_PASSWORD:
40 : case SSS_AUTHTOK_TYPE_CCFILE:
41 : case SSS_AUTHTOK_TYPE_2FA:
42 : case SSS_AUTHTOK_TYPE_SC_PIN:
43 : case SSS_AUTHTOK_TYPE_SC_KEYPAD:
44 8 : return tok->length;
45 : case SSS_AUTHTOK_TYPE_EMPTY:
46 3 : return 0;
47 : }
48 :
49 0 : return EINVAL;
50 : }
51 :
52 11 : uint8_t *sss_authtok_get_data(struct sss_auth_token *tok)
53 : {
54 11 : if (!tok) {
55 0 : return NULL;
56 : }
57 11 : return tok->data;
58 : }
59 :
60 17 : errno_t sss_authtok_get_password(struct sss_auth_token *tok,
61 : const char **pwd, size_t *len)
62 : {
63 17 : if (!tok) {
64 0 : return EFAULT;
65 : }
66 17 : switch (tok->type) {
67 : case SSS_AUTHTOK_TYPE_EMPTY:
68 2 : return ENOENT;
69 : case SSS_AUTHTOK_TYPE_PASSWORD:
70 15 : *pwd = (const char *)tok->data;
71 15 : if (len) {
72 3 : *len = tok->length - 1;
73 : }
74 15 : return EOK;
75 : case SSS_AUTHTOK_TYPE_CCFILE:
76 : case SSS_AUTHTOK_TYPE_2FA:
77 : case SSS_AUTHTOK_TYPE_SC_PIN:
78 : case SSS_AUTHTOK_TYPE_SC_KEYPAD:
79 0 : return EACCES;
80 : }
81 :
82 0 : return EINVAL;
83 : }
84 :
85 5 : errno_t sss_authtok_get_ccfile(struct sss_auth_token *tok,
86 : const char **ccfile, size_t *len)
87 : {
88 5 : if (!tok) {
89 0 : return EINVAL;
90 : }
91 5 : switch (tok->type) {
92 : case SSS_AUTHTOK_TYPE_EMPTY:
93 2 : return ENOENT;
94 : case SSS_AUTHTOK_TYPE_CCFILE:
95 3 : *ccfile = (const char *)tok->data;
96 3 : if (len) {
97 3 : *len = tok->length - 1;
98 : }
99 3 : return EOK;
100 : case SSS_AUTHTOK_TYPE_PASSWORD:
101 : case SSS_AUTHTOK_TYPE_2FA:
102 : case SSS_AUTHTOK_TYPE_SC_PIN:
103 : case SSS_AUTHTOK_TYPE_SC_KEYPAD:
104 0 : return EACCES;
105 : }
106 :
107 0 : return EINVAL;
108 : }
109 :
110 29 : static errno_t sss_authtok_set_string(struct sss_auth_token *tok,
111 : enum sss_authtok_type type,
112 : const char *context_name,
113 : const char *str, size_t len)
114 : {
115 : size_t size;
116 :
117 29 : if (len == 0) {
118 4 : len = strlen(str);
119 : } else {
120 25 : while (len > 0 && str[len - 1] == '\0') len--;
121 : }
122 :
123 29 : if (len == 0) {
124 : /* we do not allow zero length typed tokens */
125 0 : return EINVAL;
126 : }
127 :
128 29 : size = len + 1;
129 :
130 29 : tok->data = talloc_named(tok, size, "%s", context_name);
131 29 : if (!tok->data) {
132 0 : return ENOMEM;
133 : }
134 29 : memcpy(tok->data, str, len);
135 29 : tok->data[len] = '\0';
136 29 : tok->type = type;
137 29 : tok->length = size;
138 :
139 29 : return EOK;
140 :
141 : }
142 :
143 57 : void sss_authtok_set_empty(struct sss_auth_token *tok)
144 : {
145 57 : if (!tok) {
146 0 : return;
147 : }
148 57 : switch (tok->type) {
149 : case SSS_AUTHTOK_TYPE_EMPTY:
150 44 : return;
151 : case SSS_AUTHTOK_TYPE_PASSWORD:
152 : case SSS_AUTHTOK_TYPE_2FA:
153 : case SSS_AUTHTOK_TYPE_SC_PIN:
154 10 : safezero(tok->data, tok->length);
155 10 : break;
156 : case SSS_AUTHTOK_TYPE_CCFILE:
157 : case SSS_AUTHTOK_TYPE_SC_KEYPAD:
158 3 : break;
159 : }
160 :
161 13 : tok->type = SSS_AUTHTOK_TYPE_EMPTY;
162 13 : talloc_zfree(tok->data);
163 13 : tok->length = 0;
164 : }
165 :
166 22 : errno_t sss_authtok_set_password(struct sss_auth_token *tok,
167 : const char *password, size_t len)
168 : {
169 22 : sss_authtok_set_empty(tok);
170 :
171 22 : return sss_authtok_set_string(tok, SSS_AUTHTOK_TYPE_PASSWORD,
172 : "password", password, len);
173 : }
174 :
175 3 : errno_t sss_authtok_set_ccfile(struct sss_auth_token *tok,
176 : const char *ccfile, size_t len)
177 : {
178 3 : sss_authtok_set_empty(tok);
179 :
180 3 : return sss_authtok_set_string(tok, SSS_AUTHTOK_TYPE_CCFILE,
181 : "ccfile", ccfile, len);
182 : }
183 :
184 : static errno_t sss_authtok_set_2fa_from_blob(struct sss_auth_token *tok,
185 : const uint8_t *data, size_t len);
186 :
187 13 : errno_t sss_authtok_set(struct sss_auth_token *tok,
188 : enum sss_authtok_type type,
189 : const uint8_t *data, size_t len)
190 : {
191 13 : switch (type) {
192 : case SSS_AUTHTOK_TYPE_PASSWORD:
193 3 : return sss_authtok_set_password(tok, (const char *)data, len);
194 : case SSS_AUTHTOK_TYPE_CCFILE:
195 2 : return sss_authtok_set_ccfile(tok, (const char *)data, len);
196 : case SSS_AUTHTOK_TYPE_2FA:
197 5 : return sss_authtok_set_2fa_from_blob(tok, data, len);
198 : case SSS_AUTHTOK_TYPE_SC_PIN:
199 0 : return sss_authtok_set_sc_pin(tok, (const char*)data, len);
200 : case SSS_AUTHTOK_TYPE_SC_KEYPAD:
201 0 : sss_authtok_set_sc_keypad(tok);
202 0 : return EOK;
203 : case SSS_AUTHTOK_TYPE_EMPTY:
204 3 : sss_authtok_set_empty(tok);
205 3 : return EOK;
206 : }
207 :
208 0 : return EINVAL;
209 : }
210 :
211 2 : errno_t sss_authtok_copy(struct sss_auth_token *src,
212 : struct sss_auth_token *dst)
213 : {
214 2 : if (!src || !dst) {
215 0 : return EINVAL;
216 : }
217 2 : sss_authtok_set_empty(dst);
218 :
219 2 : if (src->type == SSS_AUTHTOK_TYPE_EMPTY) {
220 1 : return EOK;
221 : }
222 :
223 1 : dst->data = talloc_memdup(dst, src->data, src->length);
224 1 : if (!dst->data) {
225 0 : return ENOMEM;
226 : }
227 1 : dst->length = src->length;
228 1 : dst->type = src->type;
229 :
230 1 : return EOK;
231 : }
232 :
233 121 : struct sss_auth_token *sss_authtok_new(TALLOC_CTX *mem_ctx)
234 : {
235 : struct sss_auth_token *token;
236 :
237 121 : token = talloc_zero(mem_ctx, struct sss_auth_token);
238 121 : if (token == NULL) {
239 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
240 : }
241 :
242 121 : return token;
243 : }
244 :
245 :
246 109 : void sss_authtok_wipe_password(struct sss_auth_token *tok)
247 : {
248 109 : if (!tok || tok->type != SSS_AUTHTOK_TYPE_PASSWORD) {
249 201 : return;
250 : }
251 :
252 17 : safezero(tok->data, tok->length);
253 : }
254 :
255 10 : errno_t sss_auth_unpack_2fa_blob(TALLOC_CTX *mem_ctx,
256 : const uint8_t *blob, size_t blob_len,
257 : char **fa1, size_t *_fa1_len,
258 : char **fa2, size_t *_fa2_len)
259 : {
260 : size_t c;
261 : uint32_t fa1_len;
262 : uint32_t fa2_len;
263 :
264 10 : if (blob_len < 2 * sizeof(uint32_t)) {
265 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Blob too small.\n");
266 0 : return EINVAL;
267 : }
268 :
269 10 : c = 0;
270 10 : SAFEALIGN_COPY_UINT32(&fa1_len, blob, &c);
271 10 : SAFEALIGN_COPY_UINT32(&fa2_len, blob + c, &c);
272 :
273 10 : if (blob_len != 2 * sizeof(uint32_t) + fa1_len + fa2_len) {
274 1 : DEBUG(SSSDBG_CRIT_FAILURE, "Blob size mismatch.\n");
275 1 : return EINVAL;
276 : }
277 :
278 9 : if (fa1_len != 0) {
279 9 : *fa1 = talloc_strndup(mem_ctx, (const char *) blob + c, fa1_len);
280 9 : if (*fa1 == NULL) {
281 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
282 0 : return ENOMEM;
283 : }
284 : } else {
285 0 : *fa1 = NULL;
286 : }
287 :
288 9 : if (fa2_len != 0) {
289 9 : *fa2 = talloc_strndup(mem_ctx, (const char *) blob + c + fa1_len,
290 : fa2_len);
291 9 : if (*fa2 == NULL) {
292 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
293 0 : talloc_free(*fa1);
294 0 : return ENOMEM;
295 : }
296 : } else {
297 0 : *fa2 = NULL;
298 : }
299 :
300 : /* Re-calculate length for the case where \0 was missing in the blob */
301 9 : *_fa1_len = (*fa1 == NULL) ? 0 : strlen(*fa1);
302 9 : *_fa2_len = (*fa2 == NULL) ? 0 : strlen(*fa2);
303 :
304 9 : return EOK;
305 : }
306 :
307 5 : static errno_t sss_authtok_set_2fa_from_blob(struct sss_auth_token *tok,
308 : const uint8_t *data, size_t len)
309 : {
310 : TALLOC_CTX *tmp_ctx;
311 : int ret;
312 : char *fa1;
313 : size_t fa1_len;
314 : char *fa2;
315 : size_t fa2_len;
316 :
317 5 : tmp_ctx = talloc_new(NULL);
318 5 : if (tmp_ctx == NULL) {
319 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
320 0 : ret = ENOMEM;
321 0 : goto done;
322 : }
323 :
324 5 : ret = sss_auth_unpack_2fa_blob(tmp_ctx, data, len, &fa1, &fa1_len,
325 : &fa2, &fa2_len);
326 5 : if (ret != EOK) {
327 1 : DEBUG(SSSDBG_OP_FAILURE, "sss_auth_unpack_2fa_blob failed.\n");
328 1 : goto done;
329 : }
330 :
331 4 : ret = sss_authtok_set_2fa(tok, fa1, fa1_len, fa2, fa2_len);
332 4 : if (ret != EOK) {
333 0 : DEBUG(SSSDBG_OP_FAILURE, "sss_authtok_set_2fa failed.\n");
334 0 : goto done;
335 : }
336 :
337 4 : ret = EOK;
338 : done:
339 5 : talloc_free(tmp_ctx);
340 :
341 5 : if (ret != EOK) {
342 1 : sss_authtok_set_empty(tok);
343 : }
344 :
345 5 : return ret;
346 : }
347 :
348 7 : errno_t sss_authtok_get_2fa(struct sss_auth_token *tok,
349 : const char **fa1, size_t *fa1_len,
350 : const char **fa2, size_t *fa2_len)
351 : {
352 : size_t c;
353 : uint32_t tmp_uint32_t;
354 :
355 7 : if (tok->type != SSS_AUTHTOK_TYPE_2FA) {
356 2 : return (tok->type == SSS_AUTHTOK_TYPE_EMPTY) ? ENOENT : EACCES;
357 : }
358 :
359 5 : if (tok->length < 2 * sizeof(uint32_t)) {
360 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Blob too small.\n");
361 0 : return EINVAL;
362 : }
363 :
364 5 : c = 0;
365 5 : SAFEALIGN_COPY_UINT32(&tmp_uint32_t, tok->data, &c);
366 5 : *fa1_len = tmp_uint32_t - 1;
367 5 : SAFEALIGN_COPY_UINT32(&tmp_uint32_t, tok->data + c, &c);
368 5 : *fa2_len = tmp_uint32_t - 1;
369 :
370 5 : if (*fa1_len == 0 || *fa2_len == 0
371 5 : || tok->length != 2 * sizeof(uint32_t) + *fa1_len + *fa2_len + 2) {
372 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Blob size mismatch.\n");
373 0 : return EINVAL;
374 : }
375 :
376 5 : if (tok->data[c + *fa1_len] != '\0'
377 5 : || tok->data[c + *fa1_len + 1 + *fa2_len] != '\0') {
378 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Missing terminating null character.\n");
379 0 : return EINVAL;
380 : }
381 :
382 5 : *fa1 = (const char *) tok->data + c;
383 5 : *fa2 = (const char *) tok->data + c + *fa1_len + 1;
384 :
385 5 : return EOK;
386 : }
387 :
388 10 : errno_t sss_authtok_set_2fa(struct sss_auth_token *tok,
389 : const char *fa1, size_t fa1_len,
390 : const char *fa2, size_t fa2_len)
391 : {
392 : int ret;
393 : size_t needed_size;
394 :
395 10 : if (tok == NULL) {
396 1 : return EINVAL;
397 : }
398 :
399 9 : sss_authtok_set_empty(tok);
400 :
401 9 : ret = sss_auth_pack_2fa_blob(fa1, fa1_len, fa2, fa2_len, NULL, 0,
402 : &needed_size);
403 9 : if (ret != EAGAIN) {
404 4 : DEBUG(SSSDBG_CRIT_FAILURE,
405 : "sss_auth_pack_2fa_blob unexpectedly returned [%d].\n", ret);
406 4 : return EINVAL;
407 : }
408 :
409 5 : tok->data = talloc_size(tok, needed_size);
410 5 : if (tok->data == NULL) {
411 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_size failed.\n");
412 0 : return ENOMEM;
413 : }
414 :
415 5 : ret = sss_auth_pack_2fa_blob(fa1, fa1_len, fa2, fa2_len, tok->data,
416 : needed_size, &needed_size);
417 5 : if (ret != EOK) {
418 0 : talloc_free(tok->data);
419 0 : DEBUG(SSSDBG_OP_FAILURE, "sss_auth_pack_2fa_blob failed.\n");
420 0 : return ret;
421 : }
422 5 : tok->length = needed_size;
423 5 : tok->type = SSS_AUTHTOK_TYPE_2FA;
424 :
425 5 : return EOK;
426 : }
427 :
428 6 : errno_t sss_authtok_set_sc_pin(struct sss_auth_token *tok, const char *pin,
429 : size_t len)
430 : {
431 6 : if (tok == NULL) {
432 1 : return EFAULT;
433 : }
434 5 : if (pin == NULL) {
435 1 : return EINVAL;
436 : }
437 :
438 4 : sss_authtok_set_empty(tok);
439 :
440 4 : return sss_authtok_set_string(tok, SSS_AUTHTOK_TYPE_SC_PIN,
441 : "sc_pin", pin, len);
442 : }
443 :
444 6 : errno_t sss_authtok_get_sc_pin(struct sss_auth_token *tok, const char **pin,
445 : size_t *len)
446 : {
447 6 : if (!tok) {
448 1 : return EFAULT;
449 : }
450 5 : switch (tok->type) {
451 : case SSS_AUTHTOK_TYPE_EMPTY:
452 1 : return ENOENT;
453 : case SSS_AUTHTOK_TYPE_SC_PIN:
454 3 : *pin = (const char *)tok->data;
455 3 : if (len) {
456 3 : *len = tok->length - 1;
457 : }
458 3 : return EOK;
459 : case SSS_AUTHTOK_TYPE_PASSWORD:
460 : case SSS_AUTHTOK_TYPE_CCFILE:
461 : case SSS_AUTHTOK_TYPE_2FA:
462 : case SSS_AUTHTOK_TYPE_SC_KEYPAD:
463 1 : return EACCES;
464 : }
465 :
466 0 : return EINVAL;
467 : }
468 :
469 2 : void sss_authtok_set_sc_keypad(struct sss_auth_token *tok)
470 : {
471 2 : if (!tok) {
472 3 : return;
473 : }
474 1 : sss_authtok_set_empty(tok);
475 :
476 1 : tok->type = SSS_AUTHTOK_TYPE_SC_KEYPAD;
477 : }
|