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