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