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