-/* -*-c-*-
- *
- * $Id: key.c,v 1.1 1999/09/03 08:41:12 mdw Exp $
- *
- * Simple key management
- *
- * (c) 1999 Mark Wooding
- */
-
-/*----- Licensing notice --------------------------------------------------*
- *
- * This file is part of Catacomb.
- *
- * Catacomb is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Library General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * Catacomb is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with Catacomb; if not, write to the Free
- * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- * MA 02111-1307, USA.
- */
-
-/*----- Revision history --------------------------------------------------*
- *
- * $Log: key.c,v $
- * Revision 1.1 1999/09/03 08:41:12 mdw
- * Initial import.
- *
- */
-
-/*----- Header files ------------------------------------------------------*/
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#include <mLib/alloc.h>
-#include <mLib/base64.h>
-#include <mLib/bits.h>
-#include <mLib/crc32.h>
-#include <mLib/dstr.h>
-#include <mLib/hash.h>
-#include <mLib/lock.h>
-#include <mLib/report.h>
-#include <mLib/str.h>
-#include <mLib/sub.h>
-#include <mLib/sym.h>
-#include <mLib/url.h>
-
-#include "key.h"
-
-/*----- Useful macros -----------------------------------------------------*/
-
-#define KEY_PARANOID
-#define NOTHING
-
-#ifdef KEY_PARANOID
-# define KEY_WRITE(f, func, val) do { \
- if (!(f)->f & KF_WRITE) { \
- moan(#func " [caller error]: keyfile is readonly"); \
- errno = EROFS; \
- return val; \
- } \
- } while (0)
-#else
-# define KEY_WRITE(f, func) do { ; } while (0)
-#endif
-
-#define KEY_MODIFY(f) do { (f)->f |= KF_MODIFIED; } while (0)
-
-#define KEY_LOAD(n) ((n) * 2)
-
-/*----- Sanity checking of values -----------------------------------------*/
-
-/* --- @key_chktype@ --- *
- *
- * Arguments: @const char *type@ = pointer to a type string
- *
- * Returns: Zero if OK, -1 on error.
- *
- * Use: Checks whether a type string is OK.
- */
-
-int key_chktype(const char *type)
-{
- if (!type || !*type)
- goto fail;
- while (*type) {
- if (isspace((unsigned char)*type))
- goto fail;
- type++;
- }
- return (0);
-
-fail:
- errno = EINVAL;
- return (-1);
-}
-
-/* --- @key_chkcomment@ --- *
- *
- * Arguments: @const char *comment@ = pointer to a comment string
- *
- * Returns: Zero if OK, -1 on error.
- *
- * Use: Checks whether a comment string is OK.
- */
-
-int key_chkcomment(const char *c)
-{
- if (!c)
- return (0);
- if (!*c)
- goto fail;
- while (*c) {
- if (*c == '\n')
- goto fail;
- c++;
- }
- return (0);
-
-fail:
- errno = EINVAL;
- return (-1);
-}
-
-/*----- Low-level fiddling ------------------------------------------------*/
-
-/* --- @insert@ --- *
- *
- * Arguments: @key_file *f@ = pointer to file structure
- * @const char *type@ = type of key to insert
- * @const void *k@ = pointer to key data
- * @size_t ksz@ = size of key data
- * @time_t exp@ = expiry time for key
- * @time_t del@ = deletion time for key
- *
- * Returns: Pointer to key block to fill in the rest of, or zero.
- *
- * Use: Inserts a key into a key file.
- */
-
-static key *insert(key_file *f,
- const char *type,
- const void *k, size_t ksz,
- time_t exp, time_t del)
-{
- uint32 id;
- key *kk;
- key_type *t;
-
- /* --- Sanity preservatives --- */
-
- if (key_chktype(type))
- return (0);
-
- /* --- Insert into the id table --- */
-
- {
- hash_base **bin, **b;
-
- CRC32(id, 0, k, ksz);
- bin = HASH_BIN(&f->byid, id);
- for (b = bin; *b; b = &(*b)->next) {
- if ((*b)->hash == id) {
- errno = EEXIST;
- return (0);
- }
- }
-
- kk = CREATE(key);
- kk->_b.next = 0;
- *b = &kk->_b;
- kk->_b.hash = id;
- }
-
- /* --- Extend the table --- */
-
- if (f->idload > 0)
- f->idload--;
- else if (hash_extend(&f->byid))
- f->idload = KEY_LOAD(f->byid.mask / 2);
-
- /* --- Initialize the key block --- */
-
- kk->id = id;
- kk->k = sub_alloc(ksz);
- memcpy(kk->k, k, ksz);
- kk->ksz = ksz;
- kk->type = xstrdup(type);
- kk->exp = exp;
- kk->del = del;
- sym_create(&kk->a);
- kk->c = 0;
-
- /* --- Insert into the type table --- */
-
- {
- unsigned found;
- t = sym_find(&f->bytype, type, -1, sizeof(*t), &found);
- if (!found) {
- t->k = kk;
- kk->next = 0;
- } else {
- key **p = &t->k;
- if (exp != KEXP_FOREVER) {
- while (*p && (*p)->exp != KEXP_EXPIRE && (*p)->exp > exp)
- p = &(*p)->next;
- }
- kk->next = *p;
- *p = kk;
- }
- }
-
- return (kk);
-}
-
-/*----- Iteration and iterators -------------------------------------------*/
-
-/* --- @key_mkiter@ --- *
- *
- * Arguments: @key_iter *i@ = pointer to iterator object
- * @key_file *f@ = pointer to file structure
- *
- * Returns: ---
- *
- * Use: Initializes a key iterator. The keys are returned by
- * @key_next@.
- */
-
-void key_mkiter(key_iter *i, key_file *f)
-{
- HASH_MKITER(&i->i, &f->byid);
- i->t = time(0);
-}
-
-/* --- @key_next@ --- *
- *
- * Arguments: @key_iter *i@ = pointer to iterator object
- *
- * Returns: Pointer to next key, or null.
- *
- * Use: Returns the next key in some arbitrary sequence.
- */
-
-key *key_next(key_iter *i)
-{
- hash_base *b;
- key *k;
- do {
- HASH_NEXT(&i->i, b);
- k = (key *)b;
- } while (k && KEY_EXPIRED(i->t, k->exp) && KEY_DELETED(i->t, k->del));
- return (k);
-}
-
-/* --- @key_mkattriter@ --- *
- *
- * Arguments: @key_attriter *i@ = pointer to attribute iterator
- * @key_file *f@ = pointer to key file
- * @key *k@ = pointer to key
- *
- * Returns: ---
- *
- * Use: Initializes an attribute iterator. The attributes are
- * returned by @key_nextattr@.
- */
-
-void key_mkattriter(key_attriter *i, key_file *f, key *k)
-{
- sym_mkiter(&i->i, &k->a);
-}
-
-/* --- @key_nextattr@ --- *
- *
- * Arguments: @key_attriter *i@ = pointer to attribute iterator
- * @const char **n, **v@ = pointers to name and value
- *
- * Returns: Zero if no attribute available, or nonzero if returned OK.
- *
- * Use: Returns the next attribute.
- */
-
-int key_nextattr(key_attriter *i, const char **n, const char **v)
-{
- key_attr *a = sym_next(&i->i);
- if (!a)
- return (0);
- *n = SYM_NAME(a);
- *v = a->p;
- return (1);
-}
-
-/*----- Lookup ------------------------------------------------------------*/
-
-/* --- @key_bytype@ --- *
- *
- * Arguments: @key_file *f@ = key file we want a key from
- * @const char *type@ = type string for desired key
- *
- * Returns: Pointer to the best key to use, or null.
- *
- * Use: Looks up a key by its type. Returns the key with the latest
- * expiry time. This function will not return an expired key.
- */
-
-key *key_bytype(key_file *f, const char *type)
-{
- time_t now = time(0);
- key *k;
- key_type *t;
-
- if ((t = sym_find(&f->bytype, type, -1, 0, 0)) == 0)
- return (0);
- for (k = t->k; k && KEY_EXPIRED(now, k->exp); k = k->next)
- ;
- return (k);
-}
-
-/* --- @key_byid@ --- *
- *
- * Arguments: @key_file *f@ = key file to find a key from
- * @uint32 id@ = id to look for
- *
- * Returns: Key with matching id.
- *
- * Use: Returns a key given its id. This function will return an
- * expired key, but not a deleted one.
- */
-
-key *key_byid(key_file *f, uint32 id)
-{
- time_t t = time(0);
- hash_base **bin, *b;
-
- bin = HASH_BIN(&f->byid, id);
- for (b = *bin; b; b = b->next) {
- if (b->hash == id) {
- key *k = (key *)b;
- if (KEY_EXPIRED(t, k->exp) && KEY_DELETED(t, k->del))
- return (0);
- return (k);
- }
- }
- return (0);
-}
-
-/*----- Attributes --------------------------------------------------------*/
-
-/* --- @key_getattr@ --- *
- *
- * Arguments: @key_file *f@ = pointer to file
- * @key *k@ = pointer to key
- * @const char *n@ = pointer to attribute name
- *
- * Returns: Pointer to attribute value, or null if not found.
- *
- * Use: Returns the value of a key attribute.
- */
-
-const char *key_getattr(key_file *f, key *k, const char *n)
-{
- key_attr *a;
- if ((a = sym_find(&k->a, n, -1, 0, 0)) == 0)
- return (0);
- return (a->p);
-}
-
-/* --- @key_putattr@ --- *
- *
- * Arguments: @key_file *f@ = pointer to file
- * @key *k@ = pointer to key
- * @const char *n@ = pointer to attribute name
- * @const char *v@ = pointer to attribute value or null
- *
- * Returns: ---
- *
- * Use: Inserts an attribute on a key. If an attribute with the same
- * name already exists, it is deleted. Setting a null value
- * removes the attribute.
- */
-
-void key_putattr(key_file *f, key *k, const char *n, const char *v)
-{
- key_attr *a;
- unsigned found;
-
- KEY_WRITE(f, key_putattr, NOTHING);
-
- if (v) {
- a = sym_find(&k->a, n, -1, sizeof(*a), &found);
- if (found)
- free(a->p);
- a->p = xstrdup(v);
- } else if ((a = sym_find(&k->a, n, -1, 0, 0)) != 0) {
- free(a->p);
- sym_remove(&k->a, a);
- }
-
- KEY_MODIFY(f);
-}
-
-/* --- @key_setcomment@ --- *
- *
- * Arguments: @key_file *f@ = pointer to key file block
- * @key *k@ = pointer to key block
- * @const char *c@ = pointer to comment to set, or zero
- *
- * Returns: ---
- *
- * Use: Replaces the key's current comment with a new one.
- */
-
-void key_setcomment(key_file *f, key *k, const char *c)
-{
- KEY_WRITE(f, key_setcomment, NOTHING);
- if (key_chkcomment(c))
- return;
- if (k->c)
- free(k->c);
- if (c)
- k->c = xstrdup(c);
- else
- k->c = 0;
- KEY_MODIFY(f);
-}
-
-/*----- Low-level file I/O ------------------------------------------------*/
-
-/* --- @key_merge@ --- *
- *
- * Arguments: @key_file *f@ = pointer to file structure
- * @const char *file@ = name of file (for error messages)
- * @FILE *fp@ = file handle to read from
- *
- * Returns: ---
- *
- * Use: Reads keys from a file, and inserts them into the file.
- */
-
-void key_merge(key_file *f, const char *file, FILE *fp)
-{
- int line = 0;
- dstr l = DSTR_INIT;
- dstr d = DSTR_INIT;
- dstr n = DSTR_INIT, v = DSTR_INIT;
-
- KEY_WRITE(f, key_merge, NOTHING);
-
- for (; dstr_putline(&l, fp) != EOF; DRESET(&l)) {
- char *vf[6];
- char *p = l.buf;
- key *k;
-
- /* --- Skip blank lines and comments --- *
- *
- * Quite what they're doing in what ought to be an automatically-
- * maintained file I don't know.
- */
-
- line++;
- while (isspace((unsigned char)*p))
- p++;
- if (!*p || *p == '#')
- continue;
-
- /* --- Break the line into fields --- *
- *
- * There are currently six fields of interest:
- *
- * * The key's type tag.
- * * The actual key data itself.
- * * The key expiry time.
- * * The key deletion time.
- * * The attributes field.
- * * Any further comments.
- *
- * All but the last field can contain no spaces.
- */
-
- {
- int n = str_split(p, vf, 5, &vf[5]);
- if (n < 4) {
- moan("key file `%s', line %i: too few fields", file, line);
- continue;
- }
- }
-
- /* --- Decode various bits and insert the key --- */
-
- {
- base64_ctx b;
- time_t exp, del;
-
- base64_init(&b);
- base64_decode(&b, vf[1], strlen(vf[1]), &d);
- base64_decode(&b, 0, 0, &d);
-
- exp = (time_t)atol(vf[2]);
- del = (time_t)atol(vf[3]);
-
- if ((k = insert(f, vf[0], d.buf, d.len, exp, del)) == 0)
- continue;
- DRESET(&d);
- }
-
- /* --- Parse up the attributes, if specified --- */
-
- if (vf[4]) {
- url_dctx uc;
- for (url_initdec(&uc, vf[4]); url_dec(&uc, &n, &v); ) {
- key_putattr(f, k, n.buf, v.buf);
- DRESET(&n); DRESET(&v);
- }
- }
-
- /* --- Insert the comment --- */
-
- if (vf[5])
- k->c = xstrdup(vf[5]);
- }
-
- /* --- Extensive tidying up now required --- */
-
- dstr_destroy(&l);
- dstr_destroy(&d);
- dstr_destroy(&n);
- dstr_destroy(&v);
- KEY_MODIFY(f);
-}
-
-/* --- @key_extract@ --- *
- *
- * Arguments: @key_file *f@ = pointer to file structure
- * @key *k@ = key to extract
- * @FILE *fp@ = file to write on
- *
- * Returns: Zero if OK, EOF on error.
- *
- * Use: Extracts a key to an ouptut file.
- */
-
-int key_extract(key_file *f, key *k, FILE *fp)
-{
- dstr d = DSTR_INIT;
-
- /* --- Encode the key and write the easy stuff --- */
-
- {
- base64_ctx b;
- base64_init(&b);
- b.indent = "";
- base64_encode(&b, k->k, k->ksz, &d);
- base64_encode(&b, 0, 0, &d);
- DPUTZ(&d);
- fprintf(fp, "%s %s %li %li ",
- k->type, d.buf, (long)k->exp, (long)k->del);
- DRESET(&d);
- }
-
- /* --- Output the attributes --- */
-
- {
- int none = 1;
- sym_iter i;
- key_attr *a;
- url_ectx uc;
-
- url_initenc(&uc);
- for (sym_mkiter(&i, &k->a); (a = sym_next(&i)) != 0; ) {
- none = 0;
- url_enc(&uc, &d, SYM_NAME(a), a->p);
- }
- if (none)
- DPUTS(&d, "-");
- DWRITE(&d, fp);
- }
-
- dstr_destroy(&d);
- if (k->c) {
- putc(' ', fp);
- fputs(k->c, fp);
- }
- putc('\n', fp);
- return (ferror(fp) ? EOF : 0);
-}
-
-/* --- @fdcopy@ --- *
- *
- * Arguments: @int source@ = source file descriptor
- * @int dest@ = destination file descriptor
- *
- * Returns: Zero if OK, nonzero otherwise.
- *
- * Use: Copies data from one file descriptor to another.
- */
-
-static int fdcopy(int source, int dest)
-{
- char buf[4096];
-
- if (lseek(source, 0, SEEK_SET) < 0||
- lseek(dest, 0, SEEK_SET) < 0 ||
- ftruncate(dest, 0) < 0)
- return (-1);
- for (;;) {
- int n = read(source, buf, sizeof(buf));
- if (n < 0)
- return (-1);
- else if (n == 0)
- break;
- else if (write(dest, buf, n) < 0)
- return (-1);
- }
- return (0);
-}
-
-/* --- @key_write@ --- *
- *
- * Arguments: @key_file *f@ = pointer to key file block
- *
- * Returns: A @KWRITE_@ code indicating how well it worked.
- *
- * Use: Writes a key file's data back to the actual file. This code
- * is extremely careful about error handling. It should usually
- * be able to back out somewhere sensible, but it can tell when
- * it's got itself into a real pickle and starts leaving well
- * alone.
- *
- * Callers, please make sure that you ring alarm bells when this
- * function returns @KWRITE_BROKEN@.
- */
-
-int key_write(key_file *f)
-{
- dstr n_older = DSTR_INIT, n_old = DSTR_INIT, n_new = DSTR_INIT;
- int rc = KWRITE_FAIL;
-
- if (!(f->f & KF_MODIFIED))
- return (KWRITE_OK);
-
- /* --- Write a new key file out --- *
- *
- * Check for an error after each key line. This ought to be enough.
- * Checking after each individual byte write and @fprintf@ isn't much fun.
- */
-
- dstr_putf(&n_new, "%s.new", f->name);
-
- {
- key *k;
- key_iter i;
- FILE *fp;
-
- if ((fp = fopen(n_new.buf, "w")) == 0)
- goto fail_open;
-
- for (key_mkiter(&i, f); (k = key_next(&i)) != 0; ) {
- if (key_extract(f, k, fp)) {
- fclose(fp);
- goto fail_write;
- }
- }
-
- if (fclose(fp))
- goto fail_write;
- }
-
- /* --- Set up the other filenames --- */
-
- dstr_putf(&n_older, "%s.older", f->name);
- dstr_putf(&n_old, "%s.old", f->name);
-
- /* --- Move the current backup on one --- *
- *
- * If the `older' file exists, then we're in need of attention.
- */
-
- {
- struct stat st;
- if (stat(n_older.buf, &st) == 0 || errno != ENOENT) {
- errno = EEXIST;
- rc = KWRITE_BROKEN;
- goto fail_shift;
- }
- if (rename(n_old.buf, n_older.buf) && errno != ENOENT)
- goto fail_shift;
- }
-
- /* --- Copy the current file to the backup --- */
-
- {
- int fd;
- if ((fd = open(n_old.buf, O_WRONLY | O_CREAT | O_EXCL, 0600)) < 0)
- goto fail_backup;
- if (fdcopy(f->fd, fd)) {
- close(fd);
- goto fail_backup;
- }
- if (close(fd))
- goto fail_backup;
- }
-
- /* --- Copy the newly created file to the current one --- *
- *
- * This is the dangerous bit.
- */
-
- {
- int fd;
- if ((fd = open(n_new.buf, O_RDONLY)) < 0)
- goto fail_update;
- if (fdcopy(fd, f->fd)) {
- close(fd);
- goto fail_update;
- }
- close(fd);
- if (fsync(f->fd))
- goto fail_update;
- }
-
- /* --- Clean up --- *
- *
- * Remove the `new' file and the `older' backup. Then we're done.
- */
-
- unlink(n_new.buf);
- unlink(n_older.buf);
- return (KWRITE_OK);
-
- /* --- Failure while writing the new key file --- *
- *
- * I need to copy the backup back. If that fails then I'm really stuffed.
- * If not, then I might as well try to get the backups sorted back out
- * again.
- */
-
-fail_update:
- {
- int fd;
- int e = errno;
-
- if ((fd = open(n_old.buf, O_RDONLY)) < 0)
- rc = KWRITE_BROKEN;
- else if (fdcopy(fd, f->fd)) {
- close(fd);
- rc = KWRITE_BROKEN;
- } else {
- close(fd);
- if (fsync(f->fd))
- rc = KWRITE_BROKEN;
- }
-
- errno = e;
- if (rc == KWRITE_BROKEN)
- goto fail_shift;
- }
- /* Now drop through */
-
- /* --- Failure while writing the new backup --- *
- *
- * The new backup isn't any use. Try to recover the old one.
- */
-
-fail_backup:
- {
- int e = errno;
- unlink(n_old.buf);
- if (rename(n_older.buf, n_old.buf) && errno != ENOENT)
- rc = KWRITE_BROKEN;
- errno = e;
- }
- /* Now drop through */
-
- /* --- Failure while demoting the current backup --- *
- *
- * Leave the completed output file there for the operator in case he wants
- * to clean up.
- */
-
-fail_shift:
- dstr_destroy(&n_new);
- dstr_destroy(&n_old);
- dstr_destroy(&n_older);
- return (rc);
-
-/* --- Failure during write of new data --- *
- *
- * Clean up the new file and return. These errors can never cause
- * breakage.
- */
-
-fail_write:
- unlink(n_new.buf);
- fail_open:
- dstr_destroy(&n_new);
- return (rc);
-}
-
-/*----- Opening and closing files -----------------------------------------*/
-
-/* --- @key_open@ --- *
- *
- * Arguments: @key_file *f@ = pointer to file structure to initialize
- * @const char *file@ = pointer to the file name
- * @int how@ = opening options (@KOPEN_*@).
- *
- * Returns: Zero if it worked, nonzero otherwise.
- *
- * Use: Opens a key file, reads its contents, and stores them in a
- * structure. The file is locked appropriately until closed
- * using @key_close@. On an error, everything is cleared away
- * tidily. If the file is opened with @KOPEN_WRITE@, it's
- * created if necessary, with read and write permissions for its
- * owner only.
- */
-
-int key_open(key_file *f, const char *file, int how)
-{
- FILE *fp;
-
- /* --- Trivial bits of initialization --- */
-
- f->f = 0;
- f->name = xstrdup(file);
-
- /* --- Open the file and get the lock --- */
-
- {
- int of, lf;
- const char *ff;
- int fd;
-
- /* --- Lots of things depend on whether we're writing --- */
-
- switch (how) {
- case KOPEN_READ:
- of = O_RDONLY;
- lf = LOCK_NONEXCL;
- ff = "r";
- break;
- case KOPEN_WRITE:
- of = O_RDWR | O_CREAT;
- lf = LOCK_EXCL;
- ff = "r+";
- break;
- default:
- errno = EINVAL;
- return (-1);
- }
-
- if ((fd = open(file, of, 0600)) < 0)
- return (-1);
- if (fcntl(fd, F_SETFD, 1) < 0 ||
- lock_file(fd, lf) < 0 || (fp = fdopen(fd, ff)) == 0) {
- close(fd);
- return (-1);
- }
- f->fd = fd;
- }
-
- /* --- Read the file of keys into the table --- */
-
- hash_create(&f->byid, 64);
- f->idload = KEY_LOAD(64);
- sym_create(&f->bytype);
- f->f |= KF_WRITE;
- key_merge(f, file, fp);
- if (how == KOPEN_READ)
- f->f &= ~(KF_WRITE | KF_MODIFIED);
- else
- f->f &= ~KF_MODIFIED;
-
- /* --- Close the file if only needed for reading --- */
-
- if (how == KOPEN_READ) {
- f->fp = 0;
- fclose(fp);
- } else
- f->fp = fp;
-
- return (0);
-}
-
-/* --- @key_close@ --- *
- *
- * Arguments: @key_file *f@ = pointer to key file block
- *
- * Returns: A @KWRITE_@ code indicating how it went.
- *
- * Use: Frees all the key data, writes any changes. Make sure that
- * all hell breaks loose if this returns @KWRITE_BROKEN@.
- */
-
-int key_close(key_file *f)
-{
- int e;
- hash_base *b;
- hash_iter i;
-
- if ((e = key_write(f)) != KWRITE_OK)
- return (e);
-
- /* --- Free all the individual keys --- */
-
- for (hash_mkiter(&i, &f->byid); (b = hash_next(&i)) != 0; ) {
- sym_iter j;
- key_attr *a;
- key *k = (key *)b;
-
- sub_free(k->k, k->ksz);
- free(k->type);
- if (k->c)
- free(k->c);
- for (sym_mkiter(&j, &k->a); (a = sym_next(&j)) != 0; )
- free(a->p);
- sym_destroy(&k->a);
- DESTROY(k);
- }
- hash_destroy(&f->byid);
- sym_destroy(&f->bytype);
-
- if (f->fp)
- fclose(f->fp);
- free(f->name);
- return (KWRITE_OK);
-}
-
-/*----- Miscellaneous functions -------------------------------------------*/
-
-/* --- @key_new@ ---
- *
- * Arguments: @key_file *f@ = pointer to key file
- * @const char *type@ = the type of this key
- * @const void *k@ = pointer to key data
- * @size_t ksz@ = size of key data
- * @time_t exp@ = when the key expires
- * @const char *c@ = textual comment to attach
- *
- * Returns: Key block containing new data, or null if it couldn't be
- * done.
- *
- * Use: Attaches a new key to a key file. You must have a writable
- * key file for this to work.
- *
- * The type is a key type string. This interface doesn't care
- * about how type strings are formatted: it just treats them as
- * opaque gobs of text. Clients are advised to choose some
- * standard for representing key types, though.
- *
- * The key can be any old binary mess.
- *
- * The expiry time should either be a time in the future, or the
- * magic value @KEXP_FOREVER@ which means `never expire this
- * key'. Be careful with `forever' keys. If I were you, I'd
- * use a more sophisticated key management system than this for
- * them.
- *
- * The comment can be any old text not containing newlines or
- * nulls. This interface doesn't impose any length restrictions
- * on comment lengths.
- */
-
-key *key_new(key_file *f, const char *type,
- const void *k, size_t ksz,
- time_t exp, const char *c)
-{
- key *kk;
- time_t t = time(0);
-
- KEY_WRITE(f, key_new, 0);
-
- if (KEY_EXPIRED(t, exp) ||
- key_chktype(type) || key_chkcomment(c) ||
- (kk = insert(f, type, k, ksz, exp, KEXP_UNUSED)) == 0)
- return (0);
- if (c)
- kk->c = xstrdup(c);
- KEY_MODIFY(f);
- return (kk);
-}
-
-/* --- @key_delete@ --- *
- *
- * Arguments: @key_file *f@ = pointer to file block
- * @key *k@ = key to delete
- *
- * Returns: ---
- *
- * Use: Removes the given key from the list. The key file must be
- * writable. (Due to the horridness of the data structures,
- * deleted keys aren't actually removed, just marked so that
- * they can't be looked up or iterated over. One upshot of
- * this is that they don't get written back to the file when
- * it's closed.)
- */
-
-void key_delete(key_file *f, key *k)
-{
- KEY_WRITE(f, key_delete, NOTHING);
- k->exp = KEXP_EXPIRE;
- k->del = KEXP_UNUSED;
- KEY_MODIFY(f);
-}
-
-/* --- @key_expire@ --- *
- *
- * Arguments: @key_file *f@ = pointer to file block
- * @key *k@ = pointer to key block
- *
- * Returns: ---
- *
- * Use: Immediately marks the key as expired. It may be removed
- * immediately, if it is no longer required, and will be removed
- * by a tidy operation when it is no longer required. The key
- * file must be writable.
- */
-
-void key_expire(key_file *f, key *k)
-{
- KEY_WRITE(f, key_expire, NOTHING);
- k->exp = KEXP_EXPIRE;
- if (k->del == KEXP_FOREVER)
- k->del = KEXP_UNUSED;
- KEY_MODIFY(f);
-}
-
-/* --- @key_used@ --- *
- *
- * Arguments: @key_file *f@ = pointer to key file
- * @key *k@ = pointer to key block
- * @time_t t@ = when key can be removed
- *
- * Returns: Zero if OK, nonzero on failure.
- *
- * Use: Marks a key as being required until a given time. Even
- * though the key may expire before then (and won't be returned
- * by type after that time), it will still be available when
- * requested explicitly by id. The key file must be writable.
- *
- * The only (current) reason for failure is attempting to use
- * a key which can expire for something which can't.
- */
-
-int key_used(key_file *f, key *k, time_t t)
-{
- KEY_WRITE(f, key_used, -1);
- if (t == KEXP_FOREVER) {
- if (k->exp != KEXP_FOREVER) {
- errno = EINVAL;
- return (-1);
- }
- } else if (k->del >= t)
- return (0);
-
- k->del = t;
- KEY_MODIFY(f);
- return (0);
-}
-
-/*----- That's all, folks -------------------------------------------------*/