Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/plugins/preauth/pkinit/pkinit_identity.c
34923 views
1
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
/*
3
* COPYRIGHT (C) 2007
4
* THE REGENTS OF THE UNIVERSITY OF MICHIGAN
5
* ALL RIGHTS RESERVED
6
*
7
* Permission is granted to use, copy, create derivative works
8
* and redistribute this software and such derivative works
9
* for any purpose, so long as the name of The University of
10
* Michigan is not used in any advertising or publicity
11
* pertaining to the use of distribution of this software
12
* without specific, written prior authorization. If the
13
* above copyright notice or any other identification of the
14
* University of Michigan is included in any copy of any
15
* portion of this software, then the disclaimer below must
16
* also be included.
17
*
18
* THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
19
* FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
20
* PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
21
* MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
22
* WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
23
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
24
* REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
25
* FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
26
* CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
27
* OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
28
* IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
29
* SUCH DAMAGES.
30
*/
31
32
#include "pkinit.h"
33
34
static void
35
free_list(char **list)
36
{
37
size_t i;
38
39
if (list == NULL)
40
return;
41
42
for (i = 0; list[i] != NULL; i++)
43
free(list[i]);
44
free(list);
45
}
46
47
static krb5_error_code
48
copy_list(char ***dst, char **src)
49
{
50
size_t i;
51
char **newlist;
52
53
if (dst == NULL)
54
return EINVAL;
55
*dst = NULL;
56
57
if (src == NULL)
58
return 0;
59
60
for (i = 0; src[i] != NULL; i++);
61
62
newlist = calloc(1, (i + 1) * sizeof(*newlist));
63
if (newlist == NULL)
64
return ENOMEM;
65
66
for (i = 0; src[i] != NULL; i++) {
67
newlist[i] = strdup(src[i]);
68
if (newlist[i] == NULL)
69
goto cleanup;
70
}
71
newlist[i] = NULL;
72
*dst = newlist;
73
return 0;
74
cleanup:
75
free_list(newlist);
76
return ENOMEM;
77
}
78
79
char *
80
idtype2string(int idtype)
81
{
82
switch(idtype) {
83
case IDTYPE_FILE: return "FILE"; break;
84
case IDTYPE_DIR: return "DIR"; break;
85
case IDTYPE_PKCS11: return "PKCS11"; break;
86
case IDTYPE_PKCS12: return "PKCS12"; break;
87
case IDTYPE_ENVVAR: return "ENV"; break;
88
default: return "INVALID"; break;
89
}
90
}
91
92
char *
93
catype2string(int catype)
94
{
95
switch(catype) {
96
case CATYPE_ANCHORS: return "ANCHORS"; break;
97
case CATYPE_INTERMEDIATES: return "INTERMEDIATES"; break;
98
case CATYPE_CRLS: return "CRLS"; break;
99
default: return "INVALID"; break;
100
}
101
}
102
103
krb5_error_code
104
pkinit_init_identity_opts(pkinit_identity_opts **idopts)
105
{
106
pkinit_identity_opts *opts = NULL;
107
108
*idopts = NULL;
109
opts = calloc(1, sizeof(pkinit_identity_opts));
110
if (opts == NULL)
111
return ENOMEM;
112
113
opts->identity = NULL;
114
opts->anchors = NULL;
115
opts->intermediates = NULL;
116
opts->crls = NULL;
117
118
opts->cert_filename = NULL;
119
opts->key_filename = NULL;
120
#ifndef WITHOUT_PKCS11
121
opts->p11_module_name = NULL;
122
opts->slotid = PK_NOSLOT;
123
opts->token_label = NULL;
124
opts->cert_id_string = NULL;
125
opts->cert_label = NULL;
126
#endif
127
128
*idopts = opts;
129
130
return 0;
131
}
132
133
krb5_error_code
134
pkinit_dup_identity_opts(pkinit_identity_opts *src_opts,
135
pkinit_identity_opts **dest_opts)
136
{
137
pkinit_identity_opts *newopts;
138
krb5_error_code retval;
139
140
*dest_opts = NULL;
141
retval = pkinit_init_identity_opts(&newopts);
142
if (retval)
143
return retval;
144
145
retval = ENOMEM;
146
147
if (src_opts->identity != NULL) {
148
newopts->identity = strdup(src_opts->identity);
149
if (newopts->identity == NULL)
150
goto cleanup;
151
}
152
153
retval = copy_list(&newopts->anchors, src_opts->anchors);
154
if (retval)
155
goto cleanup;
156
157
retval = copy_list(&newopts->intermediates,src_opts->intermediates);
158
if (retval)
159
goto cleanup;
160
161
retval = copy_list(&newopts->crls, src_opts->crls);
162
if (retval)
163
goto cleanup;
164
165
if (src_opts->cert_filename != NULL) {
166
newopts->cert_filename = strdup(src_opts->cert_filename);
167
if (newopts->cert_filename == NULL)
168
goto cleanup;
169
}
170
171
if (src_opts->key_filename != NULL) {
172
newopts->key_filename = strdup(src_opts->key_filename);
173
if (newopts->key_filename == NULL)
174
goto cleanup;
175
}
176
177
#ifndef WITHOUT_PKCS11
178
if (src_opts->p11_module_name != NULL) {
179
newopts->p11_module_name = strdup(src_opts->p11_module_name);
180
if (newopts->p11_module_name == NULL)
181
goto cleanup;
182
}
183
184
newopts->slotid = src_opts->slotid;
185
186
if (src_opts->token_label != NULL) {
187
newopts->token_label = strdup(src_opts->token_label);
188
if (newopts->token_label == NULL)
189
goto cleanup;
190
}
191
192
if (src_opts->cert_id_string != NULL) {
193
newopts->cert_id_string = strdup(src_opts->cert_id_string);
194
if (newopts->cert_id_string == NULL)
195
goto cleanup;
196
}
197
198
if (src_opts->cert_label != NULL) {
199
newopts->cert_label = strdup(src_opts->cert_label);
200
if (newopts->cert_label == NULL)
201
goto cleanup;
202
}
203
#endif
204
205
206
*dest_opts = newopts;
207
return 0;
208
cleanup:
209
pkinit_fini_identity_opts(newopts);
210
return retval;
211
}
212
213
void
214
pkinit_fini_identity_opts(pkinit_identity_opts *idopts)
215
{
216
if (idopts == NULL)
217
return;
218
219
if (idopts->identity != NULL)
220
free(idopts->identity);
221
free_list(idopts->anchors);
222
free_list(idopts->intermediates);
223
free_list(idopts->crls);
224
free_list(idopts->identity_alt);
225
226
free(idopts->cert_filename);
227
free(idopts->key_filename);
228
#ifndef WITHOUT_PKCS11
229
free(idopts->p11_module_name);
230
free(idopts->token_label);
231
free(idopts->cert_id_string);
232
free(idopts->cert_label);
233
#endif
234
free(idopts);
235
}
236
237
#ifndef WITHOUT_PKCS11
238
static krb5_error_code
239
parse_pkcs11_options(krb5_context context,
240
pkinit_identity_opts *idopts,
241
const char *residual)
242
{
243
char *s, *cp, *vp, *save;
244
krb5_error_code retval = ENOMEM;
245
246
if (residual == NULL || residual[0] == '\0')
247
return 0;
248
249
/* Split string into attr=value substrings */
250
s = strdup(residual);
251
if (s == NULL)
252
return retval;
253
254
for (cp = strtok_r(s, ":", &save); cp; cp = strtok_r(NULL, ":", &save)) {
255
vp = strchr(cp, '=');
256
257
/* If there is no "=", this is a pkcs11 module name */
258
if (vp == NULL) {
259
free(idopts->p11_module_name);
260
idopts->p11_module_name = strdup(cp);
261
if (idopts->p11_module_name == NULL)
262
goto cleanup;
263
continue;
264
}
265
*vp++ = '\0';
266
if (!strcmp(cp, "module_name")) {
267
free(idopts->p11_module_name);
268
idopts->p11_module_name = strdup(vp);
269
if (idopts->p11_module_name == NULL)
270
goto cleanup;
271
} else if (!strcmp(cp, "slotid")) {
272
long slotid = strtol(vp, NULL, 10);
273
if ((slotid == LONG_MIN || slotid == LONG_MAX) && errno != 0) {
274
retval = EINVAL;
275
goto cleanup;
276
}
277
if ((long) (int) slotid != slotid) {
278
retval = EINVAL;
279
goto cleanup;
280
}
281
idopts->slotid = slotid;
282
} else if (!strcmp(cp, "token")) {
283
free(idopts->token_label);
284
idopts->token_label = strdup(vp);
285
if (idopts->token_label == NULL)
286
goto cleanup;
287
} else if (!strcmp(cp, "certid")) {
288
free(idopts->cert_id_string);
289
idopts->cert_id_string = strdup(vp);
290
if (idopts->cert_id_string == NULL)
291
goto cleanup;
292
} else if (!strcmp(cp, "certlabel")) {
293
free(idopts->cert_label);
294
idopts->cert_label = strdup(vp);
295
if (idopts->cert_label == NULL)
296
goto cleanup;
297
}
298
}
299
retval = 0;
300
cleanup:
301
free(s);
302
return retval;
303
}
304
#endif
305
306
static krb5_error_code
307
parse_fs_options(krb5_context context,
308
pkinit_identity_opts *idopts,
309
const char *residual)
310
{
311
char *certname, *keyname, *save;
312
char *copy = NULL, *cert_filename = NULL, *key_filename = NULL;
313
krb5_error_code retval = ENOMEM;
314
315
if (residual == NULL || residual[0] == '\0' || residual[0] == ',')
316
return EINVAL;
317
318
copy = strdup(residual);
319
if (copy == NULL)
320
goto cleanup;
321
322
certname = strtok_r(copy, ",", &save);
323
if (certname == NULL)
324
goto cleanup;
325
keyname = strtok_r(NULL, ",", &save);
326
327
cert_filename = strdup(certname);
328
if (cert_filename == NULL)
329
goto cleanup;
330
331
key_filename = strdup((keyname != NULL) ? keyname : certname);
332
if (key_filename == NULL)
333
goto cleanup;
334
335
free(idopts->cert_filename);
336
free(idopts->key_filename);
337
idopts->cert_filename = cert_filename;
338
idopts->key_filename = key_filename;
339
cert_filename = key_filename = NULL;
340
retval = 0;
341
342
cleanup:
343
free(copy);
344
free(cert_filename);
345
free(key_filename);
346
return retval;
347
}
348
349
static krb5_error_code
350
parse_pkcs12_options(krb5_context context,
351
pkinit_identity_opts *idopts,
352
const char *residual)
353
{
354
krb5_error_code retval = ENOMEM;
355
356
if (residual == NULL || residual[0] == '\0')
357
return 0;
358
359
free(idopts->cert_filename);
360
idopts->cert_filename = strdup(residual);
361
if (idopts->cert_filename == NULL)
362
goto cleanup;
363
364
free(idopts->key_filename);
365
idopts->key_filename = strdup(residual);
366
if (idopts->key_filename == NULL)
367
goto cleanup;
368
369
pkiDebug("%s: cert_filename '%s' key_filename '%s'\n",
370
__FUNCTION__, idopts->cert_filename,
371
idopts->key_filename);
372
retval = 0;
373
cleanup:
374
return retval;
375
}
376
377
static krb5_error_code
378
process_option_identity(krb5_context context,
379
pkinit_plg_crypto_context plg_cryptoctx,
380
pkinit_req_crypto_context req_cryptoctx,
381
pkinit_identity_opts *idopts,
382
pkinit_identity_crypto_context id_cryptoctx,
383
krb5_principal princ, const char *value)
384
{
385
const char *residual;
386
int idtype;
387
krb5_error_code retval = 0;
388
389
TRACE_PKINIT_IDENTITY_OPTION(context, value);
390
if (value == NULL)
391
return EINVAL;
392
393
residual = strchr(value, ':');
394
if (residual != NULL) {
395
unsigned int typelen;
396
residual++; /* skip past colon */
397
typelen = residual - value;
398
if (strncmp(value, "FILE:", typelen) == 0) {
399
idtype = IDTYPE_FILE;
400
#ifndef WITHOUT_PKCS11
401
} else if (strncmp(value, "PKCS11:", typelen) == 0) {
402
idtype = IDTYPE_PKCS11;
403
#endif
404
} else if (strncmp(value, "PKCS12:", typelen) == 0) {
405
idtype = IDTYPE_PKCS12;
406
} else if (strncmp(value, "DIR:", typelen) == 0) {
407
idtype = IDTYPE_DIR;
408
} else if (strncmp(value, "ENV:", typelen) == 0) {
409
idtype = IDTYPE_ENVVAR;
410
} else {
411
pkiDebug("%s: Unsupported type while processing '%s'\n",
412
__FUNCTION__, value);
413
krb5_set_error_message(context, KRB5_PREAUTH_FAILED,
414
_("Unsupported type while processing "
415
"'%s'\n"), value);
416
return KRB5_PREAUTH_FAILED;
417
}
418
} else {
419
idtype = IDTYPE_FILE;
420
residual = value;
421
}
422
423
idopts->idtype = idtype;
424
pkiDebug("%s: idtype is %s\n", __FUNCTION__, idtype2string(idopts->idtype));
425
switch (idtype) {
426
case IDTYPE_ENVVAR:
427
return process_option_identity(context, plg_cryptoctx, req_cryptoctx,
428
idopts, id_cryptoctx, princ,
429
secure_getenv(residual));
430
break;
431
case IDTYPE_FILE:
432
retval = parse_fs_options(context, idopts, residual);
433
break;
434
case IDTYPE_PKCS12:
435
retval = parse_pkcs12_options(context, idopts, residual);
436
break;
437
#ifndef WITHOUT_PKCS11
438
case IDTYPE_PKCS11:
439
retval = parse_pkcs11_options(context, idopts, residual);
440
break;
441
#endif
442
case IDTYPE_DIR:
443
free(idopts->cert_filename);
444
idopts->cert_filename = strdup(residual);
445
if (idopts->cert_filename == NULL)
446
retval = ENOMEM;
447
break;
448
default:
449
krb5_set_error_message(context, KRB5_PREAUTH_FAILED,
450
_("Internal error parsing "
451
"X509_user_identity\n"));
452
retval = EINVAL;
453
break;
454
}
455
if (retval)
456
return retval;
457
458
retval = crypto_load_certs(context, plg_cryptoctx, req_cryptoctx, idopts,
459
id_cryptoctx, princ, TRUE);
460
if (retval)
461
return retval;
462
463
crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx, id_cryptoctx);
464
return 0;
465
}
466
467
static krb5_error_code
468
process_option_ca_crl(krb5_context context,
469
pkinit_plg_crypto_context plg_cryptoctx,
470
pkinit_req_crypto_context req_cryptoctx,
471
pkinit_identity_opts *idopts,
472
pkinit_identity_crypto_context id_cryptoctx,
473
const char *value,
474
int catype)
475
{
476
char *residual;
477
unsigned int typelen;
478
int idtype;
479
480
pkiDebug("%s: processing catype %s, value '%s'\n",
481
__FUNCTION__, catype2string(catype), value);
482
residual = strchr(value, ':');
483
if (residual == NULL) {
484
pkiDebug("No type given for '%s'\n", value);
485
return EINVAL;
486
}
487
residual++; /* skip past colon */
488
typelen = residual - value;
489
if (strncmp(value, "FILE:", typelen) == 0) {
490
idtype = IDTYPE_FILE;
491
} else if (strncmp(value, "DIR:", typelen) == 0) {
492
idtype = IDTYPE_DIR;
493
} else {
494
return ENOTSUP;
495
}
496
return crypto_load_cas_and_crls(context,
497
plg_cryptoctx,
498
req_cryptoctx,
499
idopts, id_cryptoctx,
500
idtype, catype, residual);
501
}
502
503
/*
504
* Load any identity information which doesn't require us to ask a controlling
505
* user any questions, and record the names of anything else which would
506
* require us to ask questions.
507
*/
508
krb5_error_code
509
pkinit_identity_initialize(krb5_context context,
510
pkinit_plg_crypto_context plg_cryptoctx,
511
pkinit_req_crypto_context req_cryptoctx,
512
pkinit_identity_opts *idopts,
513
pkinit_identity_crypto_context id_cryptoctx,
514
krb5_clpreauth_callbacks cb,
515
krb5_clpreauth_rock rock,
516
krb5_principal princ)
517
{
518
krb5_error_code retval = EINVAL;
519
size_t i;
520
521
pkiDebug("%s: %p %p %p\n", __FUNCTION__, context, idopts, id_cryptoctx);
522
if (!(princ &&
523
krb5_principal_compare_any_realm(context, princ,
524
krb5_anonymous_principal()))) {
525
if (idopts == NULL || id_cryptoctx == NULL)
526
goto errout;
527
528
/*
529
* If identity was specified, use that. (For the kdc, this
530
* is specified as pkinit_identity in the kdc.conf. For users,
531
* this is specified on the command line via X509_user_identity.)
532
* If a user did not specify identity on the command line,
533
* then we will try alternatives which may have been specified
534
* in the config file.
535
*/
536
if (idopts->identity != NULL) {
537
retval = process_option_identity(context, plg_cryptoctx,
538
req_cryptoctx, idopts,
539
id_cryptoctx, princ,
540
idopts->identity);
541
} else if (idopts->identity_alt != NULL) {
542
for (i = 0; retval != 0 && idopts->identity_alt[i] != NULL; i++) {
543
retval = process_option_identity(context, plg_cryptoctx,
544
req_cryptoctx, idopts,
545
id_cryptoctx, princ,
546
idopts->identity_alt[i]);
547
}
548
} else {
549
retval = KRB5_PREAUTH_FAILED;
550
krb5_set_error_message(context, retval,
551
_("No user identity options specified"));
552
pkiDebug("%s: no user identity options specified\n", __FUNCTION__);
553
goto errout;
554
}
555
} else {
556
/* We're the anonymous principal. */
557
retval = 0;
558
}
559
560
errout:
561
return retval;
562
}
563
564
/*
565
* Load identity information, including that which requires us to ask a
566
* controlling user any questions. If we have PIN/password values which
567
* correspond to a given identity, use that, otherwise, if one is available,
568
* we'll use the prompter callback.
569
*/
570
krb5_error_code
571
pkinit_identity_prompt(krb5_context context,
572
pkinit_plg_crypto_context plg_cryptoctx,
573
pkinit_req_crypto_context req_cryptoctx,
574
pkinit_identity_opts *idopts,
575
pkinit_identity_crypto_context id_cryptoctx,
576
krb5_clpreauth_callbacks cb,
577
krb5_clpreauth_rock rock,
578
int do_matching,
579
krb5_principal princ)
580
{
581
krb5_error_code retval = 0;
582
const char *signer_identity;
583
krb5_boolean valid;
584
size_t i;
585
586
pkiDebug("%s: %p %p %p\n", __FUNCTION__, context, idopts, id_cryptoctx);
587
if (!(princ &&
588
krb5_principal_compare_any_realm(context, princ,
589
krb5_anonymous_principal()))) {
590
retval = crypto_load_certs(context, plg_cryptoctx, req_cryptoctx,
591
idopts, id_cryptoctx, princ, FALSE);
592
if (retval)
593
goto errout;
594
595
if (do_matching) {
596
/*
597
* Try to select exactly one certificate based on matching
598
* criteria. Typical used for clients.
599
*/
600
retval = pkinit_cert_matching(context, plg_cryptoctx,
601
req_cryptoctx, id_cryptoctx, princ);
602
if (retval) {
603
crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
604
id_cryptoctx);
605
goto errout;
606
}
607
} else {
608
/*
609
* Tell crypto code to use the "default" identity. Typically used
610
* for KDCs.
611
*/
612
retval = crypto_cert_select_default(context, plg_cryptoctx,
613
req_cryptoctx, id_cryptoctx);
614
if (retval) {
615
crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
616
id_cryptoctx);
617
goto errout;
618
}
619
}
620
621
if (rock != NULL && cb != NULL && retval == 0) {
622
/* Save the signer identity if we're the client. */
623
if (crypto_retrieve_signer_identity(context, id_cryptoctx,
624
&signer_identity) == 0) {
625
cb->set_cc_config(context, rock, "X509_user_identity",
626
signer_identity);
627
}
628
}
629
630
retval = crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
631
id_cryptoctx);
632
if (retval)
633
goto errout;
634
} /* Not anonymous principal */
635
636
/* Require at least one successful anchor if any are specified. */
637
valid = FALSE;
638
for (i = 0; idopts->anchors != NULL && idopts->anchors[i] != NULL; i++) {
639
retval = process_option_ca_crl(context, plg_cryptoctx, req_cryptoctx,
640
idopts, id_cryptoctx,
641
idopts->anchors[i], CATYPE_ANCHORS);
642
if (!retval)
643
valid = TRUE;
644
}
645
if (retval && !valid)
646
goto errout;
647
krb5_clear_error_message(context);
648
retval = 0;
649
650
/* Require at least one successful intermediate if any are specified. */
651
valid = FALSE;
652
for (i = 0; idopts->intermediates != NULL
653
&& idopts->intermediates[i] != NULL; i++) {
654
retval = process_option_ca_crl(context, plg_cryptoctx, req_cryptoctx,
655
idopts, id_cryptoctx,
656
idopts->intermediates[i],
657
CATYPE_INTERMEDIATES);
658
if (!retval)
659
valid = TRUE;
660
}
661
if (retval && !valid)
662
goto errout;
663
krb5_clear_error_message(context);
664
retval = 0;
665
666
for (i = 0; idopts->crls != NULL && idopts->crls[i] != NULL; i++) {
667
retval = process_option_ca_crl(context, plg_cryptoctx, req_cryptoctx,
668
idopts, id_cryptoctx, idopts->crls[i],
669
CATYPE_CRLS);
670
if (retval)
671
goto errout;
672
}
673
674
errout:
675
return retval;
676
}
677
678
/*
679
* Create an entry in the passed-in list for the named identity, optionally
680
* with the specified token flag value and/or supplied password, replacing any
681
* existing entry with the same identity name.
682
*/
683
krb5_error_code
684
pkinit_set_deferred_id(pkinit_deferred_id **identities,
685
const char *identity, unsigned long ck_flags,
686
const char *password)
687
{
688
size_t i;
689
pkinit_deferred_id *out = NULL, *ids;
690
char *tmp;
691
692
/* Search for an entry that's already in the list. */
693
ids = *identities;
694
for (i = 0; ids != NULL && ids[i] != NULL; i++) {
695
if (strcmp(ids[i]->identity, identity) == 0) {
696
/* Replace its password value, then we're done. */
697
tmp = password ? strdup(password) : NULL;
698
if (password != NULL && tmp == NULL)
699
return ENOMEM;
700
ids[i]->ck_flags = ck_flags;
701
free(ids[i]->password);
702
ids[i]->password = tmp;
703
return 0;
704
}
705
}
706
707
/* Resize the list. */
708
out = realloc(ids, sizeof(*ids) * (i + 2));
709
if (out == NULL)
710
goto oom;
711
*identities = out;
712
713
/* Allocate the new final entry. */
714
out[i] = malloc(sizeof(*(out[i])));
715
if (out[i] == NULL)
716
goto oom;
717
718
/* Populate the new entry. */
719
out[i]->magic = PKINIT_DEFERRED_ID_MAGIC;
720
out[i]->identity = strdup(identity);
721
if (out[i]->identity == NULL)
722
goto oom;
723
724
out[i]->ck_flags = ck_flags;
725
out[i]->password = password ? strdup(password) : NULL;
726
if (password != NULL && out[i]->password == NULL)
727
goto oom;
728
729
/* Terminate the list. */
730
out[i + 1] = NULL;
731
return 0;
732
733
oom:
734
if (out != NULL && out[i] != NULL) {
735
free(out[i]->identity);
736
free(out[i]);
737
out[i] = NULL;
738
}
739
return ENOMEM;
740
}
741
742
/*
743
* Return a password which we've associated with the named identity, if we've
744
* stored one. Otherwise return NULL.
745
*/
746
const char *
747
pkinit_find_deferred_id(pkinit_deferred_id *identities,
748
const char *identity)
749
{
750
size_t i;
751
752
for (i = 0; identities != NULL && identities[i] != NULL; i++) {
753
if (strcmp(identities[i]->identity, identity) == 0)
754
return identities[i]->password;
755
}
756
return NULL;
757
}
758
759
/*
760
* Return the flags associated with the specified identity, or 0 if we don't
761
* have such an identity.
762
*/
763
unsigned long
764
pkinit_get_deferred_id_flags(pkinit_deferred_id *identities,
765
const char *identity)
766
{
767
size_t i;
768
769
for (i = 0; identities != NULL && identities[i] != NULL; i++) {
770
if (strcmp(identities[i]->identity, identity) == 0)
771
return identities[i]->ck_flags;
772
}
773
return 0;
774
}
775
776
/*
777
* Free a deferred_id list.
778
*/
779
void
780
pkinit_free_deferred_ids(pkinit_deferred_id *identities)
781
{
782
size_t i;
783
784
for (i = 0; identities != NULL && identities[i] != NULL; i++) {
785
free(identities[i]->identity);
786
free(identities[i]->password);
787
free(identities[i]);
788
}
789
free(identities);
790
}
791
792