3 * $Id: key.c,v 1.1 1999/09/03 08:41:12 mdw Exp $
5 * Simple key management
7 * (c) 1999 Mark Wooding
10 /*----- Licensing notice --------------------------------------------------*
12 * This file is part of Catacomb.
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.
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.
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,
30 /*----- Revision history --------------------------------------------------*
33 * Revision 1.1 1999/09/03 08:41:12 mdw
38 /*----- Header files ------------------------------------------------------*/
47 #include <sys/types.h>
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>
68 /*----- Useful macros -----------------------------------------------------*/
74 # define KEY_WRITE(f, func, val) do { \
75 if (!(f)->f & KF_WRITE) { \
76 moan(#func " [caller error]: keyfile is readonly"); \
82 # define KEY_WRITE(f, func) do { ; } while (0)
85 #define KEY_MODIFY(f) do { (f)->f |= KF_MODIFIED; } while (0)
87 #define KEY_LOAD(n) ((n) * 2)
89 /*----- Sanity checking of values -----------------------------------------*/
91 /* --- @key_chktype@ --- *
93 * Arguments: @const char *type@ = pointer to a type string
95 * Returns: Zero if OK, -1 on error.
97 * Use: Checks whether a type string is OK.
100 int key_chktype(const char *type
)
105 if (isspace((unsigned char)*type
))
116 /* --- @key_chkcomment@ --- *
118 * Arguments: @const char *comment@ = pointer to a comment string
120 * Returns: Zero if OK, -1 on error.
122 * Use: Checks whether a comment string is OK.
125 int key_chkcomment(const char *c
)
143 /*----- Low-level fiddling ------------------------------------------------*/
145 /* --- @insert@ --- *
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
154 * Returns: Pointer to key block to fill in the rest of, or zero.
156 * Use: Inserts a key into a key file.
159 static key
*insert(key_file
*f
,
161 const void *k
, size_t ksz
,
162 time_t exp
, time_t del
)
168 /* --- Sanity preservatives --- */
170 if (key_chktype(type
))
173 /* --- Insert into the id table --- */
176 hash_base
**bin
, **b
;
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
) {
193 /* --- Extend the table --- */
197 else if (hash_extend(&f
->byid
))
198 f
->idload
= KEY_LOAD(f
->byid
.mask
/ 2);
200 /* --- Initialize the key block --- */
203 kk
->k
= sub_alloc(ksz
);
204 memcpy(kk
->k
, k
, ksz
);
206 kk
->type
= xstrdup(type
);
212 /* --- Insert into the type table --- */
216 t
= sym_find(&f
->bytype
, type
, -1, sizeof(*t
), &found
);
222 if (exp
!= KEXP_FOREVER
) {
223 while (*p
&& (*p
)->exp
!= KEXP_EXPIRE
&& (*p
)->exp
> exp
)
234 /*----- Iteration and iterators -------------------------------------------*/
236 /* --- @key_mkiter@ --- *
238 * Arguments: @key_iter *i@ = pointer to iterator object
239 * @key_file *f@ = pointer to file structure
243 * Use: Initializes a key iterator. The keys are returned by
247 void key_mkiter(key_iter
*i
, key_file
*f
)
249 HASH_MKITER(&i
->i
, &f
->byid
);
253 /* --- @key_next@ --- *
255 * Arguments: @key_iter *i@ = pointer to iterator object
257 * Returns: Pointer to next key, or null.
259 * Use: Returns the next key in some arbitrary sequence.
262 key
*key_next(key_iter
*i
)
269 } while (k
&& KEY_EXPIRED(i
->t
, k
->exp
) && KEY_DELETED(i
->t
, k
->del
));
273 /* --- @key_mkattriter@ --- *
275 * Arguments: @key_attriter *i@ = pointer to attribute iterator
276 * @key_file *f@ = pointer to key file
277 * @key *k@ = pointer to key
281 * Use: Initializes an attribute iterator. The attributes are
282 * returned by @key_nextattr@.
285 void key_mkattriter(key_attriter
*i
, key_file
*f
, key
*k
)
287 sym_mkiter(&i
->i
, &k
->a
);
290 /* --- @key_nextattr@ --- *
292 * Arguments: @key_attriter *i@ = pointer to attribute iterator
293 * @const char **n, **v@ = pointers to name and value
295 * Returns: Zero if no attribute available, or nonzero if returned OK.
297 * Use: Returns the next attribute.
300 int key_nextattr(key_attriter
*i
, const char **n
, const char **v
)
302 key_attr
*a
= sym_next(&i
->i
);
310 /*----- Lookup ------------------------------------------------------------*/
312 /* --- @key_bytype@ --- *
314 * Arguments: @key_file *f@ = key file we want a key from
315 * @const char *type@ = type string for desired key
317 * Returns: Pointer to the best key to use, or null.
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.
323 key
*key_bytype(key_file
*f
, const char *type
)
325 time_t now
= time(0);
329 if ((t
= sym_find(&f
->bytype
, type
, -1, 0, 0)) == 0)
331 for (k
= t
->k
; k
&& KEY_EXPIRED(now
, k
->exp
); k
= k
->next
)
336 /* --- @key_byid@ --- *
338 * Arguments: @key_file *f@ = key file to find a key from
339 * @uint32 id@ = id to look for
341 * Returns: Key with matching id.
343 * Use: Returns a key given its id. This function will return an
344 * expired key, but not a deleted one.
347 key
*key_byid(key_file
*f
, uint32 id
)
352 bin
= HASH_BIN(&f
->byid
, id
);
353 for (b
= *bin
; b
; b
= b
->next
) {
356 if (KEY_EXPIRED(t
, k
->exp
) && KEY_DELETED(t
, k
->del
))
364 /*----- Attributes --------------------------------------------------------*/
366 /* --- @key_getattr@ --- *
368 * Arguments: @key_file *f@ = pointer to file
369 * @key *k@ = pointer to key
370 * @const char *n@ = pointer to attribute name
372 * Returns: Pointer to attribute value, or null if not found.
374 * Use: Returns the value of a key attribute.
377 const char *key_getattr(key_file
*f
, key
*k
, const char *n
)
380 if ((a
= sym_find(&k
->a
, n
, -1, 0, 0)) == 0)
385 /* --- @key_putattr@ --- *
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
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.
399 void key_putattr(key_file
*f
, key
*k
, const char *n
, const char *v
)
404 KEY_WRITE(f
, key_putattr
, NOTHING
);
407 a
= sym_find(&k
->a
, n
, -1, sizeof(*a
), &found
);
411 } else if ((a
= sym_find(&k
->a
, n
, -1, 0, 0)) != 0) {
413 sym_remove(&k
->a
, a
);
419 /* --- @key_setcomment@ --- *
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
427 * Use: Replaces the key's current comment with a new one.
430 void key_setcomment(key_file
*f
, key
*k
, const char *c
)
432 KEY_WRITE(f
, key_setcomment
, NOTHING
);
433 if (key_chkcomment(c
))
444 /*----- Low-level file I/O ------------------------------------------------*/
446 /* --- @key_merge@ --- *
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
454 * Use: Reads keys from a file, and inserts them into the file.
457 void key_merge(key_file
*f
, const char *file
, FILE *fp
)
462 dstr n
= DSTR_INIT
, v
= DSTR_INIT
;
464 KEY_WRITE(f
, key_merge
, NOTHING
);
466 for (; dstr_putline(&l
, fp
) != EOF
; DRESET(&l
)) {
471 /* --- Skip blank lines and comments --- *
473 * Quite what they're doing in what ought to be an automatically-
474 * maintained file I don't know.
478 while (isspace((unsigned char)*p
))
480 if (!*p
|| *p
== '#')
483 /* --- Break the line into fields --- *
485 * There are currently six fields of interest:
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.
494 * All but the last field can contain no spaces.
498 int n
= str_split(p
, vf
, 5, &vf
[5]);
500 moan("key file `%s', line %i: too few fields", file
, line
);
505 /* --- Decode various bits and insert the key --- */
512 base64_decode(&b
, vf
[1], strlen(vf
[1]), &d
);
513 base64_decode(&b
, 0, 0, &d
);
515 exp
= (time_t)atol(vf
[2]);
516 del
= (time_t)atol(vf
[3]);
518 if ((k
= insert(f
, vf
[0], d
.buf
, d
.len
, exp
, del
)) == 0)
523 /* --- Parse up the attributes, if specified --- */
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
);
533 /* --- Insert the comment --- */
536 k
->c
= xstrdup(vf
[5]);
539 /* --- Extensive tidying up now required --- */
548 /* --- @key_extract@ --- *
550 * Arguments: @key_file *f@ = pointer to file structure
551 * @key *k@ = key to extract
552 * @FILE *fp@ = file to write on
554 * Returns: Zero if OK, EOF on error.
556 * Use: Extracts a key to an ouptut file.
559 int key_extract(key_file
*f
, key
*k
, FILE *fp
)
563 /* --- Encode the key and write the easy stuff --- */
569 base64_encode(&b
, k
->k
, k
->ksz
, &d
);
570 base64_encode(&b
, 0, 0, &d
);
572 fprintf(fp
, "%s %s %li %li ",
573 k
->type
, d
.buf
, (long)k
->exp
, (long)k
->del
);
577 /* --- Output the attributes --- */
586 for (sym_mkiter(&i
, &k
->a
); (a
= sym_next(&i
)) != 0; ) {
588 url_enc(&uc
, &d
, SYM_NAME(a
), a
->p
);
601 return (ferror(fp
) ? EOF
: 0);
604 /* --- @fdcopy@ --- *
606 * Arguments: @int source@ = source file descriptor
607 * @int dest@ = destination file descriptor
609 * Returns: Zero if OK, nonzero otherwise.
611 * Use: Copies data from one file descriptor to another.
614 static int fdcopy(int source
, int dest
)
618 if (lseek(source
, 0, SEEK_SET
) < 0||
619 lseek(dest
, 0, SEEK_SET
) < 0 ||
620 ftruncate(dest
, 0) < 0)
623 int n
= read(source
, buf
, sizeof(buf
));
628 else if (write(dest
, buf
, n
) < 0)
634 /* --- @key_write@ --- *
636 * Arguments: @key_file *f@ = pointer to key file block
638 * Returns: A @KWRITE_@ code indicating how well it worked.
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
646 * Callers, please make sure that you ring alarm bells when this
647 * function returns @KWRITE_BROKEN@.
650 int key_write(key_file
*f
)
652 dstr n_older
= DSTR_INIT
, n_old
= DSTR_INIT
, n_new
= DSTR_INIT
;
653 int rc
= KWRITE_FAIL
;
655 if (!(f
->f
& KF_MODIFIED
))
658 /* --- Write a new key file out --- *
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.
664 dstr_putf(&n_new
, "%s.new", f
->name
);
671 if ((fp
= fopen(n_new
.buf
, "w")) == 0)
674 for (key_mkiter(&i
, f
); (k
= key_next(&i
)) != 0; ) {
675 if (key_extract(f
, k
, fp
)) {
685 /* --- Set up the other filenames --- */
687 dstr_putf(&n_older
, "%s.older", f
->name
);
688 dstr_putf(&n_old
, "%s.old", f
->name
);
690 /* --- Move the current backup on one --- *
692 * If the `older' file exists, then we're in need of attention.
697 if (stat(n_older
.buf
, &st
) == 0 || errno
!= ENOENT
) {
702 if (rename(n_old
.buf
, n_older
.buf
) && errno
!= ENOENT
)
706 /* --- Copy the current file to the backup --- */
710 if ((fd
= open(n_old
.buf
, O_WRONLY
| O_CREAT
| O_EXCL
, 0600)) < 0)
712 if (fdcopy(f
->fd
, fd
)) {
720 /* --- Copy the newly created file to the current one --- *
722 * This is the dangerous bit.
727 if ((fd
= open(n_new
.buf
, O_RDONLY
)) < 0)
729 if (fdcopy(fd
, f
->fd
)) {
738 /* --- Clean up --- *
740 * Remove the `new' file and the `older' backup. Then we're done.
747 /* --- Failure while writing the new key file --- *
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
759 if ((fd
= open(n_old
.buf
, O_RDONLY
)) < 0)
761 else if (fdcopy(fd
, f
->fd
)) {
771 if (rc
== KWRITE_BROKEN
)
774 /* Now drop through */
776 /* --- Failure while writing the new backup --- *
778 * The new backup isn't any use. Try to recover the old one.
785 if (rename(n_older
.buf
, n_old
.buf
) && errno
!= ENOENT
)
789 /* Now drop through */
791 /* --- Failure while demoting the current backup --- *
793 * Leave the completed output file there for the operator in case he wants
798 dstr_destroy(&n_new
);
799 dstr_destroy(&n_old
);
800 dstr_destroy(&n_older
);
803 /* --- Failure during write of new data --- *
805 * Clean up the new file and return. These errors can never cause
812 dstr_destroy(&n_new
);
816 /*----- Opening and closing files -----------------------------------------*/
818 /* --- @key_open@ --- *
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_*@).
824 * Returns: Zero if it worked, nonzero otherwise.
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
834 int key_open(key_file
*f
, const char *file
, int how
)
838 /* --- Trivial bits of initialization --- */
841 f
->name
= xstrdup(file
);
843 /* --- Open the file and get the lock --- */
850 /* --- Lots of things depend on whether we're writing --- */
859 of
= O_RDWR
| O_CREAT
;
868 if ((fd
= open(file
, of
, 0600)) < 0)
870 if (fcntl(fd
, F_SETFD
, 1) < 0 ||
871 lock_file(fd
, lf
) < 0 || (fp
= fdopen(fd
, ff
)) == 0) {
878 /* --- Read the file of keys into the table --- */
880 hash_create(&f
->byid
, 64);
881 f
->idload
= KEY_LOAD(64);
882 sym_create(&f
->bytype
);
884 key_merge(f
, file
, fp
);
885 if (how
== KOPEN_READ
)
886 f
->f
&= ~(KF_WRITE
| KF_MODIFIED
);
888 f
->f
&= ~KF_MODIFIED
;
890 /* --- Close the file if only needed for reading --- */
892 if (how
== KOPEN_READ
) {
901 /* --- @key_close@ --- *
903 * Arguments: @key_file *f@ = pointer to key file block
905 * Returns: A @KWRITE_@ code indicating how it went.
907 * Use: Frees all the key data, writes any changes. Make sure that
908 * all hell breaks loose if this returns @KWRITE_BROKEN@.
911 int key_close(key_file
*f
)
917 if ((e
= key_write(f
)) != KWRITE_OK
)
920 /* --- Free all the individual keys --- */
922 for (hash_mkiter(&i
, &f
->byid
); (b
= hash_next(&i
)) != 0; ) {
927 sub_free(k
->k
, k
->ksz
);
931 for (sym_mkiter(&j
, &k
->a
); (a
= sym_next(&j
)) != 0; )
936 hash_destroy(&f
->byid
);
937 sym_destroy(&f
->bytype
);
945 /*----- Miscellaneous functions -------------------------------------------*/
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
956 * Returns: Key block containing new data, or null if it couldn't be
959 * Use: Attaches a new key to a key file. You must have a writable
960 * key file for this to work.
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.
967 * The key can be any old binary mess.
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
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.
980 key
*key_new(key_file
*f
, const char *type
,
981 const void *k
, size_t ksz
,
982 time_t exp
, const char *c
)
987 KEY_WRITE(f
, key_new
, 0);
989 if (KEY_EXPIRED(t
, exp
) ||
990 key_chktype(type
) || key_chkcomment(c
) ||
991 (kk
= insert(f
, type
, k
, ksz
, exp
, KEXP_UNUSED
)) == 0)
999 /* --- @key_delete@ --- *
1001 * Arguments: @key_file *f@ = pointer to file block
1002 * @key *k@ = key to delete
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
1014 void key_delete(key_file
*f
, key
*k
)
1016 KEY_WRITE(f
, key_delete
, NOTHING
);
1017 k
->exp
= KEXP_EXPIRE
;
1018 k
->del
= KEXP_UNUSED
;
1022 /* --- @key_expire@ --- *
1024 * Arguments: @key_file *f@ = pointer to file block
1025 * @key *k@ = pointer to key block
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.
1035 void key_expire(key_file
*f
, key
*k
)
1037 KEY_WRITE(f
, key_expire
, NOTHING
);
1038 k
->exp
= KEXP_EXPIRE
;
1039 if (k
->del
== KEXP_FOREVER
)
1040 k
->del
= KEXP_UNUSED
;
1044 /* --- @key_used@ --- *
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
1050 * Returns: Zero if OK, nonzero on failure.
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.
1057 * The only (current) reason for failure is attempting to use
1058 * a key which can expire for something which can't.
1061 int key_used(key_file
*f
, key
*k
, time_t t
)
1063 KEY_WRITE(f
, key_used
, -1);
1064 if (t
== KEXP_FOREVER
) {
1065 if (k
->exp
!= KEXP_FOREVER
) {
1069 } else if (k
->del
>= t
)
1077 /*----- That's all, folks -------------------------------------------------*/