chiark / gitweb /
configure.ac: Replace with a new version.
[catacomb] / key-misc.c
1 /* -*-c-*-
2  *
3  * $Id$
4  *
5  * Simple key management
6  *
7  * (c) 1999 Straylight/Edgeware
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 /*----- Header files ------------------------------------------------------*/
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <time.h>
36
37 #include <mLib/bits.h>
38 #include <mLib/hash.h>
39 #include <mLib/sub.h>
40 #include <mLib/sym.h>
41
42 #include "key.h"
43
44 /*----- Useful macros -----------------------------------------------------*/
45
46 #define KEY_WRITE(f) do {                                               \
47      if (!(f)->f & KF_WRITE)                                            \
48        return (KERR_READONLY);                                          \
49    } while (0)
50
51 #define KEY_MODIFY(f) do { (f)->f |= KF_MODIFIED; } while (0)
52
53 #define KEY_LOAD(n) ((n) * 2)
54
55 /*----- Iteration and iterators -------------------------------------------*/
56
57 /* --- @key_mkiter@ --- *
58  *
59  * Arguments:   @key_iter *i@ = pointer to iterator object
60  *              @key_file *f@ = pointer to file structure
61  *
62  * Returns:     ---
63  *
64  * Use:         Initializes a key iterator.  The keys are returned by
65  *              @key_next@.
66  */
67
68 void key_mkiter(key_iter *i, key_file *f)
69 {
70   HASH_MKITER(&i->i, &f->byid);
71   i->t = time(0);
72 }
73
74 /* --- @key_next@ --- *
75  *
76  * Arguments:   @key_iter *i@ = pointer to iterator object
77  *
78  * Returns:     Pointer to next key, or null.
79  *
80  * Use:         Returns the next key in some arbitrary sequence.
81  */
82
83 key *key_next(key_iter *i)
84 {
85   hash_base *b;
86   key *k;
87   do {
88     HASH_NEXT(&i->i, b);
89     k = (key *)b;
90   } while (k && KEY_EXPIRED(i->t, k->exp) && KEY_EXPIRED(i->t, k->del));
91   return (k);
92 }
93
94 /*----- Lookup ------------------------------------------------------------*/
95
96 /* --- @key_bytype@ --- *
97  *
98  * Arguments:   @key_file *f@ = key file we want a key from
99  *              @const char *type@ = type string for desired key
100  *
101  * Returns:     Pointer to the best key to use, or null.
102  *
103  * Use:         Looks up a key by its type.  Returns the key with the latest
104  *              expiry time.  This function will not return an expired key.
105  */
106
107 key *key_bytype(key_file *f, const char *type)
108 {
109   time_t now = time(0);
110   key *k;
111   key_ref *kr;
112
113   if ((kr = sym_find(&f->bytype, type, -1, 0, 0)) == 0)
114     return (0);
115   for (k = kr->k; k && KEY_EXPIRED(now, k->exp); k = k->next)
116     ;
117   return (k);
118 }
119
120 /* --- @key_byid@ --- *
121  *
122  * Arguments:   @key_file *f@ = key file to find a key from
123  *              @uint32 id@ = id to look for
124  *
125  * Returns:     Key with matching id.
126  *
127  * Use:         Returns a key given its id.  This function will return an
128  *              expired key, but not a deleted one.
129  */
130
131 key *key_byid(key_file *f, uint32 id)
132 {
133   time_t t = time(0);
134   hash_base **bin, *b;
135
136   bin = HASH_BIN(&f->byid, id);
137   for (b = *bin; b; b = b->next) {
138     if (b->hash == id) {
139       key *k = (key *)b;
140       if (KEY_EXPIRED(t, k->exp) && KEY_EXPIRED(t, k->del))
141         return (0);
142       return (k);
143     }
144   }
145   return (0);
146 }
147
148 /* --- @key_bytag@ --- *
149  *
150  * Arguments:   @key_file *f@ = key file to find a key from
151  *              @const char *tag@ = pointer to tag string
152  *
153  * Returns:     Key with matching id or tag.
154  *
155  * Use:         Returns a key given its tag or id.  This function will return
156  *              an expired key, but not a deleted one.
157  */
158
159 key *key_bytag(key_file *f, const char *tag)
160 {
161   time_t t = time(0);
162   char *p;
163   uint32 id;
164   key_ref *kr = sym_find(&f->bytag, tag, -1, 0, 0);
165
166   if (kr && !(KEY_EXPIRED(t, kr->k->exp) && KEY_EXPIRED(t, kr->k->del)))
167     return (kr->k);
168   id = strtoul(tag, &p, 16);
169   if (!*p)
170     return (key_byid(f, id));
171   return (key_bytype(f, tag));
172 }
173
174 /* --- @key_qtag@ --- *
175  *
176  * Arguments:   @key_file *f@ = key file to find a key from
177  *              @const char *tag@ = pointer to tag string
178  *              @dstr *d@ = pointer to string for full tag name
179  *              @key **k@ = where to store the key pointer
180  *              @key_data ***kd@ = where to store the key data pointer
181  *
182  * Returns:     Zero if OK, nonzero if it failed.
183  *
184  * Use:         Performs a full lookup on a qualified tag name.  The tag is
185  *              qualified by the names of subkeys, separated by dots.  Hence,
186  *              a qualified tag is ID|TAG[.TAG...].  The various result
187  *              pointers can be null to indicate that the result isn't
188  *              interesting.
189  */
190
191 int key_qtag(key_file *f, const char *tag, dstr *d, key **k, key_data ***kd)
192 {
193   dstr dd = DSTR_INIT;
194   const char *q;
195   key *kk;
196   key_data **kkd;
197
198   /* --- Find the end of the base tag --- */
199
200   if ((q = strchr(tag, '.')) == 0)
201     DPUTS(&dd, tag);
202   else {
203     DPUTM(&dd, tag, q - tag);
204     DPUTZ(&dd);
205     q++;
206   }
207
208   /* --- Look up the key tag --- */
209
210   if ((kk = key_bytag(f, dd.buf)) == 0) {
211     dstr_destroy(&dd);
212     return (-1);
213   }
214
215   /* --- Set the various initial bits of result up --- */
216
217   if (d)
218     key_fulltag(kk, d);
219   if (k)
220     *k = kk;
221   kkd = &kk->k;
222
223   /* --- Now dig through the rest of the tag --- */
224
225   if (q) {
226     while (*q) {
227       key_struct *ks;
228
229       /* --- Stick on the next bit of the fullqtag --- */
230
231       DRESET(&dd);
232       while (*q && *q != '.') {
233         DPUTC(&dd, *q);
234         q++;
235       }
236       DPUTZ(&dd);
237       if (d) {
238         DPUTC(d, '.');
239         DPUTD(d, &dd);
240       }
241
242       /* --- Look up the subkey --- */
243
244       if ((*kkd)->e != KENC_STRUCT) {
245         kkd = 0;
246         break;
247       }
248       if ((ks = sym_find(&(*kkd)->u.s, dd.buf, -1, 0, 0)) == 0) {
249         kkd = 0;
250         break;
251       }
252       kkd = &ks->k;
253     }
254   }
255
256   /* --- Return the results --- */
257
258   dstr_destroy(&dd);
259   if (!kkd)
260     return (-1);
261   if (kd)
262     *kd = kkd;
263   return (0);
264 }
265
266 /*----- Miscellaneous functions -------------------------------------------*/
267
268 /* --- @key_delete@ --- *
269  *
270  * Arguments:   @key_file *f@ = pointer to file block
271  *              @key *k@ = key to delete
272  *
273  * Returns:     Error code (one of the @KERR@ constants).
274  *
275  * Use:         Removes the given key from the list.  The key file must be
276  *              writable.  (Due to the horridness of the data structures,
277  *              deleted keys aren't actually removed, just marked so that
278  *              they can't be looked up or iterated over.  One upshot of
279  *              this is that they don't get written back to the file when
280  *              it's closed.)
281  */
282
283 int key_delete(key_file *f, key *k)
284 {
285   KEY_WRITE(f);
286   k->exp = KEXP_EXPIRE;
287   k->del = KEXP_EXPIRE;
288   KEY_MODIFY(f);
289   return (0);
290 }
291
292 /* --- @key_expired@ --- *
293  *
294  * Arguments:   @key *k@ = pointer to key block
295  *
296  * Returns:     Zero if the key is OK, nonzero if it's expired.
297  */
298
299 int key_expired(key *k)
300 {
301   time_t now = time(0);
302   return (KEY_EXPIRED(now, k->exp) || KEY_EXPIRED(now, k->del));
303 }
304
305 /* --- @key_expire@ --- *
306  *
307  * Arguments:   @key_file *f@ = pointer to file block
308  *              @key *k@ = pointer to key block
309  *
310  * Returns:     Error code (one of the @KERR@ constants).
311  *
312  * Use:         Immediately marks the key as expired.  It may be removed
313  *              immediately, if it is no longer required, and will be removed
314  *              by a tidy operation when it is no longer required.  The key
315  *              file must be writable.
316  */
317
318 int key_expire(key_file *f, key *k)
319 {
320   KEY_WRITE(f);
321   k->exp = KEXP_EXPIRE;
322   if (k->del == KEXP_FOREVER)
323     k->del = KEXP_EXPIRE;
324   KEY_MODIFY(f);
325   return (0);
326 }
327
328 /* --- @key_used@ --- *
329  *
330  * Arguments:   @key_file *f@ = pointer to key file
331  *              @key *k@ = pointer to key block
332  *              @time_t t@ = when key can be removed
333  *
334  * Returns:     Zero if OK, nonzero on failure.
335  *
336  * Use:         Marks a key as being required until a given time.  Even
337  *              though the key may expire before then (and won't be returned
338  *              by type after that time), it will still be available when
339  *              requested explicitly by id.  The key file must be writable.
340  *
341  *              The only (current) reason for failure is attempting to use
342  *              a key which can expire for something which can't.
343  */
344
345 int key_used(key_file *f, key *k, time_t t)
346 {
347   KEY_WRITE(f);
348   if (t == KEXP_FOREVER) {
349     if (k->exp != KEXP_FOREVER)
350       return (KERR_WILLEXPIRE);
351   } else if (k->del >= t)
352     return (0);
353
354   k->del = t;
355   KEY_MODIFY(f);
356   return (0);
357 }
358
359 /* --- @key_fingerprint@ --- *
360  *
361  * Arguments:   @key *k@ = the key to fingerprint
362  *              @ghash *h@ = the hash to use
363  *              @const key_filter *kf@ = filter to apply
364  *
365  * Returns:     Nonzero if the key slightly matched the filter.
366  *
367  * Use:         Updates the hash context with the key contents.
368  */
369
370 static int abyname(const void *a, const void *b) {
371   key_attr *const *x = a, *const *y = b;
372   return (strcmp(SYM_NAME(*x), SYM_NAME(*y)));
373 }
374
375 int key_fingerprint(key *k, ghash *h, const key_filter *kf)
376 {
377   dstr d = DSTR_INIT;
378   int rc = 0;
379   key_attr *a, **v;
380   size_t n, i;
381   sym_iter ai;
382
383   if (!key_encode(k->k, &d, kf))
384     goto done;
385   rc = 1;
386   GH_HASHSTR(h, "catacomb-key-fingerprint:");
387   GH_HASHU32(h, k->id);
388   GH_HASHSTR8(h, k->type);
389   GH_HASH(h, d.buf, d.len);
390   for (n = 0, sym_mkiter(&ai, &k->a); (a = sym_next(&ai)) != 0; n++);
391   if (n) {
392     v = xmalloc(n * sizeof(*v));
393     for (i = 0, sym_mkiter(&ai, &k->a); (a = sym_next(&ai)) != 0; i++)
394       v[i] = a;
395     qsort(v, n, sizeof(*v), abyname);
396     for (i = 0; i < n; i++) {
397       GH_HASHSTR8(h, SYM_NAME(v[i]));
398       GH_HASHSTR16(h, v[i]->p);
399     }
400     xfree(v);
401   }
402 done:
403   dstr_destroy(&d);
404   return (rc);
405 }
406
407 /*----- That's all, folks -------------------------------------------------*/