chiark / gitweb /
Initial import.
[catacomb] / key.c
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
100 int 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
111 fail:
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
125 int 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
138 fail:
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
159 static 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
247 void 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
262 key *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
285 void 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
300 int 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
323 key *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
347 key *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
377 const 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
399 void 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
430 void 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
457 void 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
559 int 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
614 static 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
650 int 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
754 fail_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
781 fail_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
797 fail_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
809 fail_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
834 int 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
911 int 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
980 key *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
1014 void 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
1035 void 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
1061 int 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 -------------------------------------------------*/