File: | db/file.c |
Warning: | line 336, column 7 Value stored to 'rc' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* file.c --- File based Shisa database. |
2 | * Copyright (C) 2002-2022 Simon Josefsson |
3 | * |
4 | * This file is part of Shishi. |
5 | * |
6 | * Shishi is free software; you can redistribute it and/or modify it |
7 | * 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 | * Shishi is distributed in the hope that it will be useful, but |
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | * General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU General Public License |
17 | * along with Shishi; if not, see http://www.gnu.org/licenses or write |
18 | * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth |
19 | * Floor, Boston, MA 02110-1301, USA |
20 | * |
21 | */ |
22 | |
23 | /* |
24 | * Theory of operation: |
25 | * |
26 | * Data is stored in the standard file system, so it is subject to |
27 | * normal access permission infrastructure, e.g. POSIX ACL or normal |
28 | * Unix file permissions. A definition of the file database looks |
29 | * like: |
30 | * |
31 | * file LOCATION OPTIONS |
32 | * |
33 | * Where LOCATION is a path name, e.g. /var/shisa. No OPTIONS are |
34 | * currently implemented. |
35 | * |
36 | * Realms are directories in LOCATION. Principals are directories in |
37 | * realm directories. Characters outside A-Za-z0-9_- are escaped |
38 | * using the URL encoding, e.g. example/host%2fwww denote the |
39 | * "host/www" principal in the "example" realm. |
40 | * |
41 | * Example file tree: |
42 | * |
43 | * LOCATION/EXAMPLE.ORG |
44 | * LOCATION/EXAMPLE.ORG/krbtgt%2fEXAMPLE.ORG |
45 | * LOCATION/EXAMPLE.ORG/host%2fwww.example.org |
46 | * LOCATION/EXAMPLE.NET |
47 | * LOCATION/EXAMPLE.NET/krbtgt%2fEXAMPLE.NET |
48 | * |
49 | */ |
50 | |
51 | /* XXX fix race conditions. */ |
52 | |
53 | #include "info.h" |
54 | |
55 | /* Get prototypes. */ |
56 | #include "file.h" |
57 | |
58 | /* Get low-level file utilities. */ |
59 | #include "fileutil.h" |
60 | |
61 | struct Shisa_file |
62 | { |
63 | char *path; |
64 | int readonly; |
65 | int allowcreate; |
66 | }; |
67 | typedef struct Shisa_file Shisa_file; |
68 | |
69 | enum |
70 | { |
71 | READ_ONLY_OPTION = 0, |
72 | ALLOW_CREATE_OPTION = 1, |
73 | THE_END |
74 | }; |
75 | |
76 | static const char *const _shisa_file_opts[] = { |
77 | /* [READ_ONLY_OPTION] = */ "read-only", |
78 | /* [ALLOW_CREATE_OPTION] = */ "allow-create", |
79 | /* [THE_END] = */ NULL((void*)0) |
80 | }; |
81 | |
82 | static int |
83 | shisa_file_cfg (Shisa * dbh, Shisa_file * info, const char *option) |
84 | { |
85 | char *opt = option ? xstrdup (option) : NULL((void*)0); |
86 | char *p = opt; |
87 | char *value; |
88 | int res; |
89 | |
90 | while (p != NULL((void*)0) && *p != '\0') |
91 | { |
92 | switch (getsubopt (&p, (char *const *) _shisa_file_opts, &value)) |
93 | { |
94 | case READ_ONLY_OPTION: |
95 | info->readonly = 1; |
96 | break; |
97 | |
98 | case ALLOW_CREATE_OPTION: |
99 | info->allowcreate = 1; |
100 | break; |
101 | |
102 | default: |
103 | shisa_info (dbh, "Unknown file database option: `%s'.", value); |
104 | res = SHISA_CFG_SYNTAX_ERROR; |
105 | goto out; |
106 | break; |
107 | } |
108 | } |
109 | |
110 | res = SHISA_OK; |
111 | |
112 | out: |
113 | free (opt); |
114 | return res; |
115 | } |
116 | |
117 | /* Initialize file backend, i.e., parse options and check if file root |
118 | exists and allocate backend handle. */ |
119 | int |
120 | shisa_file_init (Shisa * dbh, |
121 | const char *location, const char *options, void **state) |
122 | { |
123 | Shisa_file *info; |
124 | int rc; |
125 | |
126 | if (!_shisa_isdir (location)) |
127 | return SHISA_OPEN_ERROR; |
128 | |
129 | *state = info = xcalloc (1, sizeof (*info)); |
130 | |
131 | rc = shisa_file_cfg (dbh, info, options); |
132 | if (rc != SHISA_OK) |
133 | return rc; |
134 | |
135 | info->path = xstrdup (location); |
136 | |
137 | return SHISA_OK; |
138 | } |
139 | |
140 | /* Destroy backend handle. */ |
141 | void |
142 | shisa_file_done (Shisa * dbh, void *state) |
143 | { |
144 | Shisa_file *info = state; |
145 | |
146 | if (info) |
147 | free (info->path); |
148 | free (info); |
149 | } |
150 | |
151 | /* Return a list of all realm names in backend, as zero-terminated |
152 | UTF-8 strings. The caller must deallocate the strings. */ |
153 | int |
154 | shisa_file_enumerate_realms (Shisa * dbh, |
155 | void *state, char ***realms, size_t *nrealms) |
156 | { |
157 | Shisa_file *info = state; |
158 | |
159 | if (_shisa_lsdir (info->path, realms, nrealms) != 0) |
160 | return SHISA_ENUMERATE_REALM_ERROR; |
161 | |
162 | return SHISA_OK; |
163 | } |
164 | |
165 | /* Return a list of all principals in realm in backend, as |
166 | zero-terminated UTF-8 strings. The caller must deallocate the |
167 | strings. */ |
168 | int |
169 | shisa_file_enumerate_principals (Shisa * dbh, |
170 | void *state, |
171 | const char *realm, |
172 | char ***principals, size_t *nprincipals) |
173 | { |
174 | Shisa_file *info = state; |
175 | |
176 | if (!_shisa_isdir2 (info->path, realm)) |
177 | return SHISA_NO_REALM; |
178 | |
179 | if (_shisa_lsdir2 (info->path, realm, principals, nprincipals) != 0) |
180 | return SHISA_ENUMERATE_PRINCIPAL_ERROR; |
181 | |
182 | return SHISA_OK; |
183 | } |
184 | |
185 | /* Return information about specified PRINCIPAL@REALM. Can also be |
186 | used check existence of principal entry, with a NULL PH. */ |
187 | int |
188 | shisa_file_principal_find (Shisa * dbh, |
189 | void *state, |
190 | const char *realm, |
191 | const char *principal, Shisa_principal * ph) |
192 | { |
193 | Shisa_file *info = state; |
194 | |
195 | if (!_shisa_isdir3 (info->path, realm, principal)) |
196 | return SHISA_NO_PRINCIPAL; |
197 | |
198 | if (!ph) |
199 | return SHISA_OK; |
200 | |
201 | ph->notusedbefore = |
202 | _shisa_mtime4 (info->path, realm, principal, "validfrom.stamp"); |
203 | ph->isdisabled = |
204 | _shisa_isfile4 (info->path, realm, principal, "disabled.flag"); |
205 | ph->kvno = _shisa_uint32link4 (info->path, realm, principal, "latest.key"); |
206 | ph->lastinitialtgt = |
207 | _shisa_mtime4 (info->path, realm, principal, "lastinitaltgt.stamp"); |
208 | ph->lastinitialrequest = |
209 | _shisa_mtime4 (info->path, realm, principal, "lastinitial.stamp"); |
210 | ph->lasttgt = _shisa_mtime4 (info->path, realm, principal, "lasttgt.stamp"); |
211 | ph->lastrenewal = |
212 | _shisa_mtime4 (info->path, realm, principal, "lastrenewal.stamp"); |
213 | ph->passwordexpire = |
214 | _shisa_mtime4 (info->path, realm, principal, "passwordexpire.stamp"); |
215 | ph->accountexpire = |
216 | _shisa_mtime4 (info->path, realm, principal, "accountexpire.stamp"); |
217 | |
218 | return SHISA_OK; |
219 | } |
220 | |
221 | static int |
222 | realm_add (Shisa * dbh, void *state, const char *realm) |
223 | { |
224 | Shisa_file *info = state; |
225 | |
226 | if (_shisa_isdir2 (info->path, realm)) |
227 | return SHISA_ADD_REALM_EXISTS; |
228 | |
229 | if (_shisa_mkdir2 (info->path, realm) != 0) |
230 | return SHISA_ADD_REALM_ERROR; |
231 | |
232 | return SHISA_OK; |
233 | |
234 | } |
235 | |
236 | static int |
237 | principal_add (Shisa * dbh, |
238 | void *state, |
239 | const char *realm, |
240 | const char *principal, |
241 | const Shisa_principal * ph, const Shisa_key * key) |
242 | { |
243 | Shisa_file *info = state; |
244 | |
245 | if (!_shisa_isdir2 (info->path, realm)) |
246 | return SHISA_NO_REALM; |
247 | |
248 | if (_shisa_isdir3 (info->path, realm, principal)) |
249 | return SHISA_ADD_PRINCIPAL_EXISTS; |
250 | |
251 | if (_shisa_mkdir3 (info->path, realm, principal) != 0) |
252 | return SHISA_ADD_PRINCIPAL_ERROR; |
253 | |
254 | if (ph) |
255 | shisa_file_principal_update (dbh, state, realm, principal, ph); |
256 | |
257 | if (key) |
258 | shisa_file_key_add (dbh, state, realm, principal, key); |
259 | |
260 | return SHISA_OK; |
261 | } |
262 | |
263 | /* Add new PRINCIPAL@REALM with specified information and key. If |
264 | PRINCIPAL is NULL, then add realm REALM. */ |
265 | int |
266 | shisa_file_principal_add (Shisa * dbh, |
267 | void *state, |
268 | const char *realm, |
269 | const char *principal, |
270 | const Shisa_principal * ph, const Shisa_key * key) |
271 | { |
272 | int rc; |
273 | |
274 | if (principal == NULL((void*)0)) |
275 | rc = realm_add (dbh, state, realm); |
276 | else |
277 | rc = principal_add (dbh, state, realm, principal, ph, key); |
278 | |
279 | return rc; |
280 | } |
281 | |
282 | /* Modify information for specified PRINCIPAL@REALM. */ |
283 | int |
284 | shisa_file_principal_update (Shisa * dbh, |
285 | void *state, |
286 | const char *realm, |
287 | const char *principal, |
288 | const Shisa_principal * ph) |
289 | { |
290 | return SHISA_OK; |
291 | } |
292 | |
293 | static int |
294 | realm_remove (Shisa * dbh, void *state, const char *realm) |
295 | { |
296 | Shisa_file *info = state; |
297 | size_t nprincipals = 0; |
298 | int rc; |
299 | |
300 | if (!_shisa_isdir2 (info->path, realm)) |
301 | return SHISA_NO_REALM; |
302 | |
303 | rc = |
304 | shisa_file_enumerate_principals (dbh, state, realm, NULL((void*)0), &nprincipals); |
305 | if (rc != SHISA_OK) |
306 | return rc; |
307 | |
308 | if (nprincipals > 0) |
309 | return SHISA_REMOVE_REALM_NONEMPTY; |
310 | |
311 | if (_shisa_rmdir2 (info->path, realm) != 0) |
312 | return SHISA_REMOVE_REALM_ERROR; |
313 | |
314 | return SHISA_OK; |
315 | } |
316 | |
317 | static int |
318 | remove_keys (Shisa * dbh, |
319 | void *state, const char *realm, const char *principal) |
320 | { |
321 | Shisa_file *info = state; |
322 | char **files; |
323 | size_t nfiles; |
324 | size_t i; |
325 | int rc; |
326 | |
327 | files = NULL((void*)0); |
328 | nfiles = 0; |
329 | |
330 | rc = _shisa_ls4 (info->path, realm, principal, "keys", &files, &nfiles); |
331 | if (rc != SHISA_OK) |
332 | return rc; |
333 | |
334 | for (i = 0; i < nfiles; i++) |
335 | { |
336 | rc = _shisa_rm5 (info->path, realm, principal, "keys", files[i]); |
Value stored to 'rc' is never read | |
337 | free (files[i]); |
338 | } |
339 | free (files); |
340 | |
341 | rc = _shisa_rmdir4 (info->path, realm, principal, "keys"); |
342 | if (rc != SHISA_OK) |
343 | return rc; |
344 | |
345 | return SHISA_OK; |
346 | } |
347 | |
348 | #if 0 |
349 | static int |
350 | remove_info (Shisa * dbh, |
351 | void *state, const char *realm, const char *principal) |
352 | { |
353 | Shisa_file *info = state; |
354 | char **files; |
355 | size_t nfiles; |
356 | size_t i; |
357 | int rc; |
358 | |
359 | files = NULL((void*)0); |
360 | nfiles = 0; |
361 | |
362 | rc = _shisa_ls3 (info->path, realm, principal, &files, &nfiles); |
363 | if (rc != SHISA_OK) |
364 | return rc; |
365 | |
366 | for (i = 0; i < nfiles; i++) |
367 | { |
368 | rc = _shisa_rm4 (info->path, realm, principal, files[i]); |
369 | free (files[i]); |
370 | } |
371 | free (files); |
372 | |
373 | return SHISA_OK; |
374 | } |
375 | #endif |
376 | |
377 | static int |
378 | principal_remove (Shisa * dbh, |
379 | void *state, const char *realm, const char *principal) |
380 | { |
381 | Shisa_file *info = state; |
382 | int rc; |
383 | |
384 | if (!_shisa_isdir2 (info->path, realm)) |
385 | return SHISA_NO_REALM; |
386 | |
387 | if (!_shisa_isdir3 (info->path, realm, principal)) |
388 | return SHISA_NO_PRINCIPAL; |
389 | |
390 | rc = remove_keys (dbh, state, realm, principal); |
391 | if (rc != SHISA_OK) |
392 | return rc; |
393 | |
394 | if (_shisa_rmdir3 (info->path, realm, principal) != 0) |
395 | return SHISA_REMOVE_PRINCIPAL_ERROR; |
396 | |
397 | return SHISA_OK; |
398 | } |
399 | |
400 | /* Remove PRINCIPAL@REALM, or REALM if PRINCIPAL is NULL. Realms must |
401 | be empty for them to be successfully removed. */ |
402 | int |
403 | shisa_file_principal_remove (Shisa * dbh, |
404 | void *state, |
405 | const char *realm, const char *principal) |
406 | { |
407 | int rc; |
408 | |
409 | if (principal == NULL((void*)0)) |
410 | rc = realm_remove (dbh, state, realm); |
411 | else |
412 | rc = principal_remove (dbh, state, realm, principal); |
413 | |
414 | return rc; |
415 | } |
416 | |
417 | static int |
418 | read_key (Shisa * dbh, |
419 | Shisa_file * info, |
420 | const char *realm, |
421 | const char *principal, const char *keyfile, Shisa_key ** key) |
422 | { |
423 | Shisa_key tmpkey; |
424 | FILE *fh; |
425 | char *file; |
426 | size_t passwdlen; |
427 | char junk; |
428 | int rc; |
429 | |
430 | asprintf (&file, "keys/%s", keyfile); |
431 | fh = _shisa_fopen4 (info->path, realm, principal, file, "r"); |
432 | free (file); |
433 | if (!fh) |
434 | return SHISA_NO_KEY; |
435 | |
436 | memset (&tmpkey, 0, sizeof (tmpkey)); |
437 | |
438 | rc = |
439 | fscanf (fh, "%" PRIi32"i" " %zu %zu %zu %zu %d", &tmpkey.etype, |
440 | &tmpkey.keylen, &tmpkey.saltlen, &tmpkey.str2keyparamlen, |
441 | &passwdlen, &tmpkey.priority); |
442 | if (rc != 5 && rc != 6) |
443 | return SHISA_NO_KEY; |
444 | |
445 | if (rc == 5) |
446 | tmpkey.priority = 0; |
447 | |
448 | if (rc == 6) |
449 | /* We can't include '\n' in scanf format above, because any |
450 | whitespace on the next line will be skipped. */ |
451 | if (fread (&junk, 1, 1, fh) != 1 || junk != '\n') |
452 | return SHISA_NO_KEY; |
453 | |
454 | if (tmpkey.keylen > 0) |
455 | { |
456 | tmpkey.key = xmalloc (tmpkey.keylen + 1); |
457 | if (fread (tmpkey.key, 1, tmpkey.keylen, fh) != tmpkey.keylen) |
458 | return SHISA_NO_KEY; |
459 | tmpkey.key[tmpkey.keylen] = '\0'; |
460 | } |
461 | |
462 | if (tmpkey.saltlen > 0) |
463 | { |
464 | tmpkey.salt = xmalloc (tmpkey.saltlen + 1); |
465 | if (fread (tmpkey.salt, 1, tmpkey.saltlen, fh) != tmpkey.saltlen) |
466 | return SHISA_NO_KEY; |
467 | tmpkey.salt[tmpkey.saltlen] = '\0'; |
468 | } |
469 | |
470 | if (tmpkey.str2keyparamlen > 0) |
471 | { |
472 | tmpkey.str2keyparam = xmalloc (tmpkey.str2keyparamlen + 1); |
473 | if (fread (tmpkey.str2keyparam, 1, tmpkey.str2keyparamlen, fh) != |
474 | tmpkey.str2keyparamlen) |
475 | return SHISA_NO_KEY; |
476 | tmpkey.str2keyparam[tmpkey.str2keyparamlen] = '\0'; |
477 | } |
478 | |
479 | if (passwdlen > 0) |
480 | { |
481 | tmpkey.password = xmalloc (passwdlen + 1); |
482 | if (fread (tmpkey.password, 1, passwdlen, fh) != passwdlen) |
483 | return SHISA_NO_KEY; |
484 | tmpkey.password[passwdlen] = '\0'; |
485 | } |
486 | |
487 | rc = fclose (fh); |
488 | if (rc != 0) |
489 | { |
490 | perror (keyfile); |
491 | return SHISA_NO_KEY; |
492 | } |
493 | |
494 | *key = xmalloc (sizeof (**key)); |
495 | memcpy (*key, &tmpkey, sizeof (tmpkey)); |
496 | |
497 | return SHISA_OK; |
498 | } |
499 | |
500 | static int |
501 | key_match (const Shisa_key * hint, Shisa_key * key) |
502 | { |
503 | int ok = 1; |
504 | |
505 | if (hint->kvno) |
506 | ok = ok && hint->kvno == key->kvno; |
507 | if (hint->etype) |
508 | ok = ok && hint->etype == key->etype; |
509 | if (hint->keylen) |
510 | ok = ok && hint->keylen == key->keylen && |
511 | memcmp (hint->key, key->key, key->keylen) == 0; |
512 | if (hint->saltlen) |
513 | ok = ok && hint->saltlen == key->saltlen && |
514 | memcmp (hint->salt, key->salt, key->saltlen) == 0; |
515 | if (hint->str2keyparamlen) |
516 | ok = ok && hint->str2keyparamlen == key->str2keyparamlen && |
517 | memcmp (hint->str2keyparam, key->str2keyparam, |
518 | key->str2keyparamlen) == 0; |
519 | if (hint->password) |
520 | ok = ok && strcmp (hint->password, key->password) == 0; |
521 | |
522 | return ok; |
523 | } |
524 | |
525 | /* Get all keys matching HINT for specified PRINCIPAL@REALM. The |
526 | caller must deallocate the returned keys. If HINT is NULL, then |
527 | all keys are returned. */ |
528 | int |
529 | shisa_file_keys_find (Shisa * dbh, |
530 | void *state, |
531 | const char *realm, |
532 | const char *principal, |
533 | const Shisa_key * hint, |
534 | Shisa_key *** keys, size_t *nkeys) |
535 | { |
536 | Shisa_file *info = state; |
537 | Shisa_key *tmpkey; |
538 | char **files; |
539 | size_t nfiles, matched = 0; |
540 | size_t i; |
541 | int rc; |
542 | |
543 | files = NULL((void*)0); |
544 | nfiles = 0; |
545 | |
546 | rc = _shisa_ls4 (info->path, realm, principal, "keys", &files, &nfiles); |
547 | if (rc != SHISA_OK) |
548 | return SHISA_ENUMERATE_KEY_ERROR; |
549 | |
550 | if (nkeys) |
551 | *nkeys = nfiles; |
552 | if (keys) |
553 | *keys = xmalloc (nfiles * sizeof (**keys)); |
554 | for (i = 0; i < nfiles; i++) |
555 | { |
556 | if (rc == SHISA_OK && |
557 | (rc = read_key (dbh, info, realm, principal, |
558 | files[i], &tmpkey)) == SHISA_OK) |
559 | { |
560 | if (hint == NULL((void*)0) || key_match (hint, tmpkey)) |
561 | { |
562 | if (keys) |
563 | (*keys)[matched] = tmpkey; |
564 | matched++; |
565 | } |
566 | else |
567 | shisa_key_free (dbh, tmpkey); |
568 | } |
569 | free (files[i]); |
570 | } |
571 | |
572 | if (nfiles > 0) |
573 | free (files); |
574 | |
575 | if (nkeys) |
576 | *nkeys = matched; |
577 | |
578 | return rc; |
579 | } |
580 | |
581 | /* Add key for PRINCIPAL@REALM. */ |
582 | int |
583 | shisa_file_key_add (Shisa * dbh, |
584 | void *state, |
585 | const char *realm, |
586 | const char *principal, const Shisa_key * key) |
587 | { |
588 | Shisa_file *info = state; |
589 | size_t passwdlen = key && key->password ? strlen (key->password) : 0; |
590 | char *file = NULL((void*)0); |
591 | size_t num = 0; |
592 | FILE *fh; |
593 | |
594 | if (!key) |
595 | return SHISA_NO_KEY; |
596 | |
597 | if (!_shisa_isdir4 (info->path, realm, principal, "keys") && |
598 | _shisa_mkdir4 (info->path, realm, principal, "keys")) |
599 | return SHISA_NO_KEY; |
600 | |
601 | do |
602 | { |
603 | free (file); |
604 | asprintf (&file, "keys/%" PRIu32"u" "-%d-%lu.key", key->kvno, key->etype, |
605 | num++); |
606 | } |
607 | while (_shisa_isfile4 (info->path, realm, principal, file)); |
608 | fh = _shisa_fopen4 (info->path, realm, principal, file, "w"); |
609 | free (file); |
610 | if (!fh) |
611 | { |
612 | perror (file); |
613 | return SHISA_ADD_KEY_ERROR; |
614 | } |
615 | |
616 | fprintf (fh, "%" PRIi32"i" " %zu %zu %zu %zu %d\n", key->etype, key->keylen, |
617 | key->saltlen, key->str2keyparamlen, passwdlen, key->priority); |
618 | if (key->keylen > 0) |
619 | fwrite (key->key, 1, key->keylen, fh); |
620 | if (key->saltlen > 0) |
621 | fwrite (key->salt, 1, key->saltlen, fh); |
622 | if (key->str2keyparamlen > 0) |
623 | fwrite (key->str2keyparam, 1, key->str2keyparamlen, fh); |
624 | if (passwdlen > 0) |
625 | fwrite (key->password, 1, passwdlen, fh); |
626 | |
627 | fclose (fh); |
628 | |
629 | return SHISA_OK; |
630 | } |
631 | |
632 | /* Update a key for PRINCIPAL@REALM. The OLDKEY must uniquely |
633 | determine the key to update, i.e., shishi_keys_find using OLDKEY as |
634 | HINT must return exactly 1 key. */ |
635 | int |
636 | shisa_file_key_update (Shisa * dbh, |
637 | void *state, |
638 | const char *realm, |
639 | const char *principal, |
640 | const Shisa_key * oldkey, const Shisa_key * newkey) |
641 | { |
642 | return SHISA_NO_KEY; |
643 | } |
644 | |
645 | /* Remove a key for PRINCIPAL@REALM. The KEY must uniquely determine |
646 | the key to remove, i.e., shishi_keys_find using KEY as HINT must |
647 | return exactly 1 key. */ |
648 | int |
649 | shisa_file_key_remove (Shisa * dbh, |
650 | void *state, |
651 | const char *realm, |
652 | const char *principal, const Shisa_key * key) |
653 | { |
654 | Shisa_file *info = state; |
655 | Shisa_key *tmpkey; |
656 | char **files; |
657 | size_t nfiles; |
658 | size_t i; |
659 | int rc; |
660 | char *found = NULL((void*)0); |
661 | |
662 | files = NULL((void*)0); |
663 | nfiles = 0; |
664 | |
665 | rc = _shisa_ls4 (info->path, realm, principal, "keys", &files, &nfiles); |
666 | if (rc != SHISA_OK) |
667 | return rc; |
668 | |
669 | for (i = 0; i < nfiles; i++) |
670 | { |
671 | if (rc == SHISA_OK && |
672 | (rc = read_key (dbh, info, realm, principal, |
673 | files[i], &tmpkey)) == SHISA_OK) |
674 | { |
675 | if (key == NULL((void*)0) || key_match (key, tmpkey)) |
676 | { |
677 | if (found) |
678 | { |
679 | free (found); |
680 | rc = SHISA_MULTIPLE_KEY_MATCH; |
681 | } |
682 | else |
683 | found = xstrdup (files[i]); |
684 | } |
685 | shisa_key_free (dbh, tmpkey); |
686 | } |
687 | free (files[i]); |
688 | } |
689 | |
690 | if (nfiles > 0) |
691 | free (files); |
692 | |
693 | if (rc != SHISA_OK) |
694 | return rc; |
695 | |
696 | if (!found) |
697 | return SHISA_NO_KEY; |
698 | |
699 | rc = _shisa_rm5 (info->path, realm, principal, "keys", found); |
700 | free (found); |
701 | return rc; |
702 | } |