More changes. Still embryonic.
[u/mdw/catacomb] / key.c
CommitLineData
d03ab969 1/* -*-c-*-
2 *
3 * $Id: key.c,v 1.1 1999/09/03 08:41:12 mdw Exp $
4 *
5 * Simple key management
6 *
7 * (c) 1999 Mark Wooding
8 */
9
10/*----- Licensing notice --------------------------------------------------*
11 *
12 * This file is part of Catacomb.
13 *
14 * Catacomb is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Library General Public License as
16 * published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
18 *
19 * Catacomb is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
23 *
24 * You should have received a copy of the GNU Library General Public
25 * License along with Catacomb; if not, write to the Free
26 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
27 * MA 02111-1307, USA.
28 */
29
30/*----- Revision history --------------------------------------------------*
31 *
32 * $Log: key.c,v $
33 * Revision 1.1 1999/09/03 08:41:12 mdw
34 * Initial import.
35 *
36 */
37
38/*----- Header files ------------------------------------------------------*/
39
40#include <ctype.h>
41#include <errno.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <string.h>
45#include <time.h>
46
47#include <sys/types.h>
48#include <sys/time.h>
49#include <sys/stat.h>
50#include <unistd.h>
51#include <fcntl.h>
52
53#include <mLib/alloc.h>
54#include <mLib/base64.h>
55#include <mLib/bits.h>
56#include <mLib/crc32.h>
57#include <mLib/dstr.h>
58#include <mLib/hash.h>
59#include <mLib/lock.h>
60#include <mLib/report.h>
61#include <mLib/str.h>
62#include <mLib/sub.h>
63#include <mLib/sym.h>
64#include <mLib/url.h>
65
66#include "key.h"
67
68/*----- Useful macros -----------------------------------------------------*/
69
70#define KEY_PARANOID
71#define NOTHING
72
73#ifdef KEY_PARANOID
74# define KEY_WRITE(f, func, val) do { \
75 if (!(f)->f & KF_WRITE) { \
76 moan(#func " [caller error]: keyfile is readonly"); \
77 errno = EROFS; \
78 return val; \
79 } \
80 } while (0)
81#else
82# define KEY_WRITE(f, func) do { ; } while (0)
83#endif
84
85#define KEY_MODIFY(f) do { (f)->f |= KF_MODIFIED; } while (0)
86
87#define KEY_LOAD(n) ((n) * 2)
88
89/*----- Sanity checking of values -----------------------------------------*/
90
91/* --- @key_chktype@ --- *
92 *
93 * Arguments: @const char *type@ = pointer to a type string
94 *
95 * Returns: Zero if OK, -1 on error.
96 *
97 * Use: Checks whether a type string is OK.
98 */
99
100int key_chktype(const char *type)
101{
102 if (!type || !*type)
103 goto fail;
104 while (*type) {
105 if (isspace((unsigned char)*type))
106 goto fail;
107 type++;
108 }
109 return (0);
110
111fail:
112 errno = EINVAL;
113 return (-1);
114}
115
116/* --- @key_chkcomment@ --- *
117 *
118 * Arguments: @const char *comment@ = pointer to a comment string
119 *
120 * Returns: Zero if OK, -1 on error.
121 *
122 * Use: Checks whether a comment string is OK.
123 */
124
125int key_chkcomment(const char *c)
126{
127 if (!c)
128 return (0);
129 if (!*c)
130 goto fail;
131 while (*c) {
132 if (*c == '\n')
133 goto fail;
134 c++;
135 }
136 return (0);
137
138fail:
139 errno = EINVAL;
140 return (-1);
141}
142
143/*----- Low-level fiddling ------------------------------------------------*/
144
145/* --- @insert@ --- *
146 *
147 * Arguments: @key_file *f@ = pointer to file structure
148 * @const char *type@ = type of key to insert
149 * @const void *k@ = pointer to key data
150 * @size_t ksz@ = size of key data
151 * @time_t exp@ = expiry time for key
152 * @time_t del@ = deletion time for key
153 *
154 * Returns: Pointer to key block to fill in the rest of, or zero.
155 *
156 * Use: Inserts a key into a key file.
157 */
158
159static key *insert(key_file *f,
160 const char *type,
161 const void *k, size_t ksz,
162 time_t exp, time_t del)
163{
164 uint32 id;
165 key *kk;
166 key_type *t;
167
168 /* --- Sanity preservatives --- */
169
170 if (key_chktype(type))
171 return (0);
172
173 /* --- Insert into the id table --- */
174
175 {
176 hash_base **bin, **b;
177
178 CRC32(id, 0, k, ksz);
179 bin = HASH_BIN(&f->byid, id);
180 for (b = bin; *b; b = &(*b)->next) {
181 if ((*b)->hash == id) {
182 errno = EEXIST;
183 return (0);
184 }
185 }
186
187 kk = CREATE(key);
188 kk->_b.next = 0;
189 *b = &kk->_b;
190 kk->_b.hash = id;
191 }
192
193 /* --- Extend the table --- */
194
195 if (f->idload > 0)
196 f->idload--;
197 else if (hash_extend(&f->byid))
198 f->idload = KEY_LOAD(f->byid.mask / 2);
199
200 /* --- Initialize the key block --- */
201
202 kk->id = id;
203 kk->k = sub_alloc(ksz);
204 memcpy(kk->k, k, ksz);
205 kk->ksz = ksz;
206 kk->type = xstrdup(type);
207 kk->exp = exp;
208 kk->del = del;
209 sym_create(&kk->a);
210 kk->c = 0;
211
212 /* --- Insert into the type table --- */
213
214 {
215 unsigned found;
216 t = sym_find(&f->bytype, type, -1, sizeof(*t), &found);
217 if (!found) {
218 t->k = kk;
219 kk->next = 0;
220 } else {
221 key **p = &t->k;
222 if (exp != KEXP_FOREVER) {
223 while (*p && (*p)->exp != KEXP_EXPIRE && (*p)->exp > exp)
224 p = &(*p)->next;
225 }
226 kk->next = *p;
227 *p = kk;
228 }
229 }
230
231 return (kk);
232}
233
234/*----- Iteration and iterators -------------------------------------------*/
235
236/* --- @key_mkiter@ --- *
237 *
238 * Arguments: @key_iter *i@ = pointer to iterator object
239 * @key_file *f@ = pointer to file structure
240 *
241 * Returns: ---
242 *
243 * Use: Initializes a key iterator. The keys are returned by
244 * @key_next@.
245 */
246
247void key_mkiter(key_iter *i, key_file *f)
248{
249 HASH_MKITER(&i->i, &f->byid);
250 i->t = time(0);
251}
252
253/* --- @key_next@ --- *
254 *
255 * Arguments: @key_iter *i@ = pointer to iterator object
256 *
257 * Returns: Pointer to next key, or null.
258 *
259 * Use: Returns the next key in some arbitrary sequence.
260 */
261
262key *key_next(key_iter *i)
263{
264 hash_base *b;
265 key *k;
266 do {
267 HASH_NEXT(&i->i, b);
268 k = (key *)b;
269 } while (k && KEY_EXPIRED(i->t, k->exp) && KEY_DELETED(i->t, k->del));
270 return (k);
271}
272
273/* --- @key_mkattriter@ --- *
274 *
275 * Arguments: @key_attriter *i@ = pointer to attribute iterator
276 * @key_file *f@ = pointer to key file
277 * @key *k@ = pointer to key
278 *
279 * Returns: ---
280 *
281 * Use: Initializes an attribute iterator. The attributes are
282 * returned by @key_nextattr@.
283 */
284
285void key_mkattriter(key_attriter *i, key_file *f, key *k)
286{
287 sym_mkiter(&i->i, &k->a);
288}
289
290/* --- @key_nextattr@ --- *
291 *
292 * Arguments: @key_attriter *i@ = pointer to attribute iterator
293 * @const char **n, **v@ = pointers to name and value
294 *
295 * Returns: Zero if no attribute available, or nonzero if returned OK.
296 *
297 * Use: Returns the next attribute.
298 */
299
300int key_nextattr(key_attriter *i, const char **n, const char **v)
301{
302 key_attr *a = sym_next(&i->i);
303 if (!a)
304 return (0);
305 *n = SYM_NAME(a);
306 *v = a->p;
307 return (1);
308}
309
310/*----- Lookup ------------------------------------------------------------*/
311
312/* --- @key_bytype@ --- *
313 *
314 * Arguments: @key_file *f@ = key file we want a key from
315 * @const char *type@ = type string for desired key
316 *
317 * Returns: Pointer to the best key to use, or null.
318 *
319 * Use: Looks up a key by its type. Returns the key with the latest
320 * expiry time. This function will not return an expired key.
321 */
322
323key *key_bytype(key_file *f, const char *type)
324{
325 time_t now = time(0);
326 key *k;
327 key_type *t;
328
329 if ((t = sym_find(&f->bytype, type, -1, 0, 0)) == 0)
330 return (0);
331 for (k = t->k; k && KEY_EXPIRED(now, k->exp); k = k->next)
332 ;
333 return (k);
334}
335
336/* --- @key_byid@ --- *
337 *
338 * Arguments: @key_file *f@ = key file to find a key from
339 * @uint32 id@ = id to look for
340 *
341 * Returns: Key with matching id.
342 *
343 * Use: Returns a key given its id. This function will return an
344 * expired key, but not a deleted one.
345 */
346
347key *key_byid(key_file *f, uint32 id)
348{
349 time_t t = time(0);
350 hash_base **bin, *b;
351
352 bin = HASH_BIN(&f->byid, id);
353 for (b = *bin; b; b = b->next) {
354 if (b->hash == id) {
355 key *k = (key *)b;
356 if (KEY_EXPIRED(t, k->exp) && KEY_DELETED(t, k->del))
357 return (0);
358 return (k);
359 }
360 }
361 return (0);
362}
363
364/*----- Attributes --------------------------------------------------------*/
365
366/* --- @key_getattr@ --- *
367 *
368 * Arguments: @key_file *f@ = pointer to file
369 * @key *k@ = pointer to key
370 * @const char *n@ = pointer to attribute name
371 *
372 * Returns: Pointer to attribute value, or null if not found.
373 *
374 * Use: Returns the value of a key attribute.
375 */
376
377const char *key_getattr(key_file *f, key *k, const char *n)
378{
379 key_attr *a;
380 if ((a = sym_find(&k->a, n, -1, 0, 0)) == 0)
381 return (0);
382 return (a->p);
383}
384
385/* --- @key_putattr@ --- *
386 *
387 * Arguments: @key_file *f@ = pointer to file
388 * @key *k@ = pointer to key
389 * @const char *n@ = pointer to attribute name
390 * @const char *v@ = pointer to attribute value or null
391 *
392 * Returns: ---
393 *
394 * Use: Inserts an attribute on a key. If an attribute with the same
395 * name already exists, it is deleted. Setting a null value
396 * removes the attribute.
397 */
398
399void key_putattr(key_file *f, key *k, const char *n, const char *v)
400{
401 key_attr *a;
402 unsigned found;
403
404 KEY_WRITE(f, key_putattr, NOTHING);
405
406 if (v) {
407 a = sym_find(&k->a, n, -1, sizeof(*a), &found);
408 if (found)
409 free(a->p);
410 a->p = xstrdup(v);
411 } else if ((a = sym_find(&k->a, n, -1, 0, 0)) != 0) {
412 free(a->p);
413 sym_remove(&k->a, a);
414 }
415
416 KEY_MODIFY(f);
417}
418
419/* --- @key_setcomment@ --- *
420 *
421 * Arguments: @key_file *f@ = pointer to key file block
422 * @key *k@ = pointer to key block
423 * @const char *c@ = pointer to comment to set, or zero
424 *
425 * Returns: ---
426 *
427 * Use: Replaces the key's current comment with a new one.
428 */
429
430void key_setcomment(key_file *f, key *k, const char *c)
431{
432 KEY_WRITE(f, key_setcomment, NOTHING);
433 if (key_chkcomment(c))
434 return;
435 if (k->c)
436 free(k->c);
437 if (c)
438 k->c = xstrdup(c);
439 else
440 k->c = 0;
441 KEY_MODIFY(f);
442}
443
444/*----- Low-level file I/O ------------------------------------------------*/
445
446/* --- @key_merge@ --- *
447 *
448 * Arguments: @key_file *f@ = pointer to file structure
449 * @const char *file@ = name of file (for error messages)
450 * @FILE *fp@ = file handle to read from
451 *
452 * Returns: ---
453 *
454 * Use: Reads keys from a file, and inserts them into the file.
455 */
456
457void key_merge(key_file *f, const char *file, FILE *fp)
458{
459 int line = 0;
460 dstr l = DSTR_INIT;
461 dstr d = DSTR_INIT;
462 dstr n = DSTR_INIT, v = DSTR_INIT;
463
464 KEY_WRITE(f, key_merge, NOTHING);
465
466 for (; dstr_putline(&l, fp) != EOF; DRESET(&l)) {
467 char *vf[6];
468 char *p = l.buf;
469 key *k;
470
471 /* --- Skip blank lines and comments --- *
472 *
473 * Quite what they're doing in what ought to be an automatically-
474 * maintained file I don't know.
475 */
476
477 line++;
478 while (isspace((unsigned char)*p))
479 p++;
480 if (!*p || *p == '#')
481 continue;
482
483 /* --- Break the line into fields --- *
484 *
485 * There are currently six fields of interest:
486 *
487 * * The key's type tag.
488 * * The actual key data itself.
489 * * The key expiry time.
490 * * The key deletion time.
491 * * The attributes field.
492 * * Any further comments.
493 *
494 * All but the last field can contain no spaces.
495 */
496
497 {
498 int n = str_split(p, vf, 5, &vf[5]);
499 if (n < 4) {
500 moan("key file `%s', line %i: too few fields", file, line);
501 continue;
502 }
503 }
504
505 /* --- Decode various bits and insert the key --- */
506
507 {
508 base64_ctx b;
509 time_t exp, del;
510
511 base64_init(&b);
512 base64_decode(&b, vf[1], strlen(vf[1]), &d);
513 base64_decode(&b, 0, 0, &d);
514
515 exp = (time_t)atol(vf[2]);
516 del = (time_t)atol(vf[3]);
517
518 if ((k = insert(f, vf[0], d.buf, d.len, exp, del)) == 0)
519 continue;
520 DRESET(&d);
521 }
522
523 /* --- Parse up the attributes, if specified --- */
524
525 if (vf[4]) {
526 url_dctx uc;
527 for (url_initdec(&uc, vf[4]); url_dec(&uc, &n, &v); ) {
528 key_putattr(f, k, n.buf, v.buf);
529 DRESET(&n); DRESET(&v);
530 }
531 }
532
533 /* --- Insert the comment --- */
534
535 if (vf[5])
536 k->c = xstrdup(vf[5]);
537 }
538
539 /* --- Extensive tidying up now required --- */
540
541 dstr_destroy(&l);
542 dstr_destroy(&d);
543 dstr_destroy(&n);
544 dstr_destroy(&v);
545 KEY_MODIFY(f);
546}
547
548/* --- @key_extract@ --- *
549 *
550 * Arguments: @key_file *f@ = pointer to file structure
551 * @key *k@ = key to extract
552 * @FILE *fp@ = file to write on
553 *
554 * Returns: Zero if OK, EOF on error.
555 *
556 * Use: Extracts a key to an ouptut file.
557 */
558
559int key_extract(key_file *f, key *k, FILE *fp)
560{
561 dstr d = DSTR_INIT;
562
563 /* --- Encode the key and write the easy stuff --- */
564
565 {
566 base64_ctx b;
567 base64_init(&b);
568 b.indent = "";
569 base64_encode(&b, k->k, k->ksz, &d);
570 base64_encode(&b, 0, 0, &d);
571 DPUTZ(&d);
572 fprintf(fp, "%s %s %li %li ",
573 k->type, d.buf, (long)k->exp, (long)k->del);
574 DRESET(&d);
575 }
576
577 /* --- Output the attributes --- */
578
579 {
580 int none = 1;
581 sym_iter i;
582 key_attr *a;
583 url_ectx uc;
584
585 url_initenc(&uc);
586 for (sym_mkiter(&i, &k->a); (a = sym_next(&i)) != 0; ) {
587 none = 0;
588 url_enc(&uc, &d, SYM_NAME(a), a->p);
589 }
590 if (none)
591 DPUTS(&d, "-");
592 DWRITE(&d, fp);
593 }
594
595 dstr_destroy(&d);
596 if (k->c) {
597 putc(' ', fp);
598 fputs(k->c, fp);
599 }
600 putc('\n', fp);
601 return (ferror(fp) ? EOF : 0);
602}
603
604/* --- @fdcopy@ --- *
605 *
606 * Arguments: @int source@ = source file descriptor
607 * @int dest@ = destination file descriptor
608 *
609 * Returns: Zero if OK, nonzero otherwise.
610 *
611 * Use: Copies data from one file descriptor to another.
612 */
613
614static int fdcopy(int source, int dest)
615{
616 char buf[4096];
617
618 if (lseek(source, 0, SEEK_SET) < 0||
619 lseek(dest, 0, SEEK_SET) < 0 ||
620 ftruncate(dest, 0) < 0)
621 return (-1);
622 for (;;) {
623 int n = read(source, buf, sizeof(buf));
624 if (n < 0)
625 return (-1);
626 else if (n == 0)
627 break;
628 else if (write(dest, buf, n) < 0)
629 return (-1);
630 }
631 return (0);
632}
633
634/* --- @key_write@ --- *
635 *
636 * Arguments: @key_file *f@ = pointer to key file block
637 *
638 * Returns: A @KWRITE_@ code indicating how well it worked.
639 *
640 * Use: Writes a key file's data back to the actual file. This code
641 * is extremely careful about error handling. It should usually
642 * be able to back out somewhere sensible, but it can tell when
643 * it's got itself into a real pickle and starts leaving well
644 * alone.
645 *
646 * Callers, please make sure that you ring alarm bells when this
647 * function returns @KWRITE_BROKEN@.
648 */
649
650int key_write(key_file *f)
651{
652 dstr n_older = DSTR_INIT, n_old = DSTR_INIT, n_new = DSTR_INIT;
653 int rc = KWRITE_FAIL;
654
655 if (!(f->f & KF_MODIFIED))
656 return (KWRITE_OK);
657
658 /* --- Write a new key file out --- *
659 *
660 * Check for an error after each key line. This ought to be enough.
661 * Checking after each individual byte write and @fprintf@ isn't much fun.
662 */
663
664 dstr_putf(&n_new, "%s.new", f->name);
665
666 {
667 key *k;
668 key_iter i;
669 FILE *fp;
670
671 if ((fp = fopen(n_new.buf, "w")) == 0)
672 goto fail_open;
673
674 for (key_mkiter(&i, f); (k = key_next(&i)) != 0; ) {
675 if (key_extract(f, k, fp)) {
676 fclose(fp);
677 goto fail_write;
678 }
679 }
680
681 if (fclose(fp))
682 goto fail_write;
683 }
684
685 /* --- Set up the other filenames --- */
686
687 dstr_putf(&n_older, "%s.older", f->name);
688 dstr_putf(&n_old, "%s.old", f->name);
689
690 /* --- Move the current backup on one --- *
691 *
692 * If the `older' file exists, then we're in need of attention.
693 */
694
695 {
696 struct stat st;
697 if (stat(n_older.buf, &st) == 0 || errno != ENOENT) {
698 errno = EEXIST;
699 rc = KWRITE_BROKEN;
700 goto fail_shift;
701 }
702 if (rename(n_old.buf, n_older.buf) && errno != ENOENT)
703 goto fail_shift;
704 }
705
706 /* --- Copy the current file to the backup --- */
707
708 {
709 int fd;
710 if ((fd = open(n_old.buf, O_WRONLY | O_CREAT | O_EXCL, 0600)) < 0)
711 goto fail_backup;
712 if (fdcopy(f->fd, fd)) {
713 close(fd);
714 goto fail_backup;
715 }
716 if (close(fd))
717 goto fail_backup;
718 }
719
720 /* --- Copy the newly created file to the current one --- *
721 *
722 * This is the dangerous bit.
723 */
724
725 {
726 int fd;
727 if ((fd = open(n_new.buf, O_RDONLY)) < 0)
728 goto fail_update;
729 if (fdcopy(fd, f->fd)) {
730 close(fd);
731 goto fail_update;
732 }
733 close(fd);
734 if (fsync(f->fd))
735 goto fail_update;
736 }
737
738 /* --- Clean up --- *
739 *
740 * Remove the `new' file and the `older' backup. Then we're done.
741 */
742
743 unlink(n_new.buf);
744 unlink(n_older.buf);
745 return (KWRITE_OK);
746
747 /* --- Failure while writing the new key file --- *
748 *
749 * I need to copy the backup back. If that fails then I'm really stuffed.
750 * If not, then I might as well try to get the backups sorted back out
751 * again.
752 */
753
754fail_update:
755 {
756 int fd;
757 int e = errno;
758
759 if ((fd = open(n_old.buf, O_RDONLY)) < 0)
760 rc = KWRITE_BROKEN;
761 else if (fdcopy(fd, f->fd)) {
762 close(fd);
763 rc = KWRITE_BROKEN;
764 } else {
765 close(fd);
766 if (fsync(f->fd))
767 rc = KWRITE_BROKEN;
768 }
769
770 errno = e;
771 if (rc == KWRITE_BROKEN)
772 goto fail_shift;
773 }
774 /* Now drop through */
775
776 /* --- Failure while writing the new backup --- *
777 *
778 * The new backup isn't any use. Try to recover the old one.
779 */
780
781fail_backup:
782 {
783 int e = errno;
784 unlink(n_old.buf);
785 if (rename(n_older.buf, n_old.buf) && errno != ENOENT)
786 rc = KWRITE_BROKEN;
787 errno = e;
788 }
789 /* Now drop through */
790
791 /* --- Failure while demoting the current backup --- *
792 *
793 * Leave the completed output file there for the operator in case he wants
794 * to clean up.
795 */
796
797fail_shift:
798 dstr_destroy(&n_new);
799 dstr_destroy(&n_old);
800 dstr_destroy(&n_older);
801 return (rc);
802
803/* --- Failure during write of new data --- *
804 *
805 * Clean up the new file and return. These errors can never cause
806 * breakage.
807 */
808
809fail_write:
810 unlink(n_new.buf);
811 fail_open:
812 dstr_destroy(&n_new);
813 return (rc);
814}
815
816/*----- Opening and closing files -----------------------------------------*/
817
818/* --- @key_open@ --- *
819 *
820 * Arguments: @key_file *f@ = pointer to file structure to initialize
821 * @const char *file@ = pointer to the file name
822 * @int how@ = opening options (@KOPEN_*@).
823 *
824 * Returns: Zero if it worked, nonzero otherwise.
825 *
826 * Use: Opens a key file, reads its contents, and stores them in a
827 * structure. The file is locked appropriately until closed
828 * using @key_close@. On an error, everything is cleared away
829 * tidily. If the file is opened with @KOPEN_WRITE@, it's
830 * created if necessary, with read and write permissions for its
831 * owner only.
832 */
833
834int key_open(key_file *f, const char *file, int how)
835{
836 FILE *fp;
837
838 /* --- Trivial bits of initialization --- */
839
840 f->f = 0;
841 f->name = xstrdup(file);
842
843 /* --- Open the file and get the lock --- */
844
845 {
846 int of, lf;
847 const char *ff;
848 int fd;
849
850 /* --- Lots of things depend on whether we're writing --- */
851
852 switch (how) {
853 case KOPEN_READ:
854 of = O_RDONLY;
855 lf = LOCK_NONEXCL;
856 ff = "r";
857 break;
858 case KOPEN_WRITE:
859 of = O_RDWR | O_CREAT;
860 lf = LOCK_EXCL;
861 ff = "r+";
862 break;
863 default:
864 errno = EINVAL;
865 return (-1);
866 }
867
868 if ((fd = open(file, of, 0600)) < 0)
869 return (-1);
870 if (fcntl(fd, F_SETFD, 1) < 0 ||
871 lock_file(fd, lf) < 0 || (fp = fdopen(fd, ff)) == 0) {
872 close(fd);
873 return (-1);
874 }
875 f->fd = fd;
876 }
877
878 /* --- Read the file of keys into the table --- */
879
880 hash_create(&f->byid, 64);
881 f->idload = KEY_LOAD(64);
882 sym_create(&f->bytype);
883 f->f |= KF_WRITE;
884 key_merge(f, file, fp);
885 if (how == KOPEN_READ)
886 f->f &= ~(KF_WRITE | KF_MODIFIED);
887 else
888 f->f &= ~KF_MODIFIED;
889
890 /* --- Close the file if only needed for reading --- */
891
892 if (how == KOPEN_READ) {
893 f->fp = 0;
894 fclose(fp);
895 } else
896 f->fp = fp;
897
898 return (0);
899}
900
901/* --- @key_close@ --- *
902 *
903 * Arguments: @key_file *f@ = pointer to key file block
904 *
905 * Returns: A @KWRITE_@ code indicating how it went.
906 *
907 * Use: Frees all the key data, writes any changes. Make sure that
908 * all hell breaks loose if this returns @KWRITE_BROKEN@.
909 */
910
911int key_close(key_file *f)
912{
913 int e;
914 hash_base *b;
915 hash_iter i;
916
917 if ((e = key_write(f)) != KWRITE_OK)
918 return (e);
919
920 /* --- Free all the individual keys --- */
921
922 for (hash_mkiter(&i, &f->byid); (b = hash_next(&i)) != 0; ) {
923 sym_iter j;
924 key_attr *a;
925 key *k = (key *)b;
926
927 sub_free(k->k, k->ksz);
928 free(k->type);
929 if (k->c)
930 free(k->c);
931 for (sym_mkiter(&j, &k->a); (a = sym_next(&j)) != 0; )
932 free(a->p);
933 sym_destroy(&k->a);
934 DESTROY(k);
935 }
936 hash_destroy(&f->byid);
937 sym_destroy(&f->bytype);
938
939 if (f->fp)
940 fclose(f->fp);
941 free(f->name);
942 return (KWRITE_OK);
943}
944
945/*----- Miscellaneous functions -------------------------------------------*/
946
947/* --- @key_new@ ---
948 *
949 * Arguments: @key_file *f@ = pointer to key file
950 * @const char *type@ = the type of this key
951 * @const void *k@ = pointer to key data
952 * @size_t ksz@ = size of key data
953 * @time_t exp@ = when the key expires
954 * @const char *c@ = textual comment to attach
955 *
956 * Returns: Key block containing new data, or null if it couldn't be
957 * done.
958 *
959 * Use: Attaches a new key to a key file. You must have a writable
960 * key file for this to work.
961 *
962 * The type is a key type string. This interface doesn't care
963 * about how type strings are formatted: it just treats them as
964 * opaque gobs of text. Clients are advised to choose some
965 * standard for representing key types, though.
966 *
967 * The key can be any old binary mess.
968 *
969 * The expiry time should either be a time in the future, or the
970 * magic value @KEXP_FOREVER@ which means `never expire this
971 * key'. Be careful with `forever' keys. If I were you, I'd
972 * use a more sophisticated key management system than this for
973 * them.
974 *
975 * The comment can be any old text not containing newlines or
976 * nulls. This interface doesn't impose any length restrictions
977 * on comment lengths.
978 */
979
980key *key_new(key_file *f, const char *type,
981 const void *k, size_t ksz,
982 time_t exp, const char *c)
983{
984 key *kk;
985 time_t t = time(0);
986
987 KEY_WRITE(f, key_new, 0);
988
989 if (KEY_EXPIRED(t, exp) ||
990 key_chktype(type) || key_chkcomment(c) ||
991 (kk = insert(f, type, k, ksz, exp, KEXP_UNUSED)) == 0)
992 return (0);
993 if (c)
994 kk->c = xstrdup(c);
995 KEY_MODIFY(f);
996 return (kk);
997}
998
999/* --- @key_delete@ --- *
1000 *
1001 * Arguments: @key_file *f@ = pointer to file block
1002 * @key *k@ = key to delete
1003 *
1004 * Returns: ---
1005 *
1006 * Use: Removes the given key from the list. The key file must be
1007 * writable. (Due to the horridness of the data structures,
1008 * deleted keys aren't actually removed, just marked so that
1009 * they can't be looked up or iterated over. One upshot of
1010 * this is that they don't get written back to the file when
1011 * it's closed.)
1012 */
1013
1014void key_delete(key_file *f, key *k)
1015{
1016 KEY_WRITE(f, key_delete, NOTHING);
1017 k->exp = KEXP_EXPIRE;
1018 k->del = KEXP_UNUSED;
1019 KEY_MODIFY(f);
1020}
1021
1022/* --- @key_expire@ --- *
1023 *
1024 * Arguments: @key_file *f@ = pointer to file block
1025 * @key *k@ = pointer to key block
1026 *
1027 * Returns: ---
1028 *
1029 * Use: Immediately marks the key as expired. It may be removed
1030 * immediately, if it is no longer required, and will be removed
1031 * by a tidy operation when it is no longer required. The key
1032 * file must be writable.
1033 */
1034
1035void key_expire(key_file *f, key *k)
1036{
1037 KEY_WRITE(f, key_expire, NOTHING);
1038 k->exp = KEXP_EXPIRE;
1039 if (k->del == KEXP_FOREVER)
1040 k->del = KEXP_UNUSED;
1041 KEY_MODIFY(f);
1042}
1043
1044/* --- @key_used@ --- *
1045 *
1046 * Arguments: @key_file *f@ = pointer to key file
1047 * @key *k@ = pointer to key block
1048 * @time_t t@ = when key can be removed
1049 *
1050 * Returns: Zero if OK, nonzero on failure.
1051 *
1052 * Use: Marks a key as being required until a given time. Even
1053 * though the key may expire before then (and won't be returned
1054 * by type after that time), it will still be available when
1055 * requested explicitly by id. The key file must be writable.
1056 *
1057 * The only (current) reason for failure is attempting to use
1058 * a key which can expire for something which can't.
1059 */
1060
1061int key_used(key_file *f, key *k, time_t t)
1062{
1063 KEY_WRITE(f, key_used, -1);
1064 if (t == KEXP_FOREVER) {
1065 if (k->exp != KEXP_FOREVER) {
1066 errno = EINVAL;
1067 return (-1);
1068 }
1069 } else if (k->del >= t)
1070 return (0);
1071
1072 k->del = t;
1073 KEY_MODIFY(f);
1074 return (0);
1075}
1076
1077/*----- That's all, folks -------------------------------------------------*/