Uprating of the passphrase pixie.
[u/mdw/catacomb] / key-misc.c
1 /* -*-c-*-
2 *
3 * $Id: key-misc.c,v 1.5 2004/04/08 01:36:15 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 /*----- 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 while (q && *q) {
226
227 /* --- Stick on the next bit of the fullqtag --- */
228
229 DRESET(&dd);
230 while (*q && *q != '.') {
231 DPUTC(&dd, *q);
232 q++;
233 }
234 DPUTZ(&dd);
235 if (d) {
236 DPUTC(d, '.');
237 DPUTD(d, &dd);
238 }
239
240 /* --- Look up the subkey --- */
241
242 if (kkd->e != KENC_STRUCT) {
243 kkd = 0;
244 break;
245 }
246 if ((kkd = key_structfind(kkd, dd.buf)) == 0)
247 break;
248 }
249
250 /* --- Return the results --- */
251
252 if (!kkd)
253 return (-1);
254 dstr_destroy(&dd);
255 if (kd)
256 *kd = kkd;
257 return (0);
258 }
259
260 /*----- Miscellaneous functions -------------------------------------------*/
261
262 /* --- @key_delete@ --- *
263 *
264 * Arguments: @key_file *f@ = pointer to file block
265 * @key *k@ = key to delete
266 *
267 * Returns: Error code (one of the @KERR@ constants).
268 *
269 * Use: Removes the given key from the list. The key file must be
270 * writable. (Due to the horridness of the data structures,
271 * deleted keys aren't actually removed, just marked so that
272 * they can't be looked up or iterated over. One upshot of
273 * this is that they don't get written back to the file when
274 * it's closed.)
275 */
276
277 int key_delete(key_file *f, key *k)
278 {
279 KEY_WRITE(f);
280 k->exp = KEXP_EXPIRE;
281 k->del = KEXP_EXPIRE;
282 KEY_MODIFY(f);
283 return (0);
284 }
285
286 /* --- @key_expired@ --- *
287 *
288 * Arguments: @key *k@ = pointer to key block
289 *
290 * Returns: Zero if the key is OK, nonzero if it's expired.
291 */
292
293 int key_expired(key *k)
294 {
295 time_t now = time(0);
296 return (KEY_EXPIRED(now, k->exp) || KEY_EXPIRED(now, k->del));
297 }
298
299 /* --- @key_expire@ --- *
300 *
301 * Arguments: @key_file *f@ = pointer to file block
302 * @key *k@ = pointer to key block
303 *
304 * Returns: Error code (one of the @KERR@ constants).
305 *
306 * Use: Immediately marks the key as expired. It may be removed
307 * immediately, if it is no longer required, and will be removed
308 * by a tidy operation when it is no longer required. The key
309 * file must be writable.
310 */
311
312 int key_expire(key_file *f, key *k)
313 {
314 KEY_WRITE(f);
315 k->exp = KEXP_EXPIRE;
316 if (k->del == KEXP_FOREVER)
317 k->del = KEXP_EXPIRE;
318 KEY_MODIFY(f);
319 return (0);
320 }
321
322 /* --- @key_used@ --- *
323 *
324 * Arguments: @key_file *f@ = pointer to key file
325 * @key *k@ = pointer to key block
326 * @time_t t@ = when key can be removed
327 *
328 * Returns: Zero if OK, nonzero on failure.
329 *
330 * Use: Marks a key as being required until a given time. Even
331 * though the key may expire before then (and won't be returned
332 * by type after that time), it will still be available when
333 * requested explicitly by id. The key file must be writable.
334 *
335 * The only (current) reason for failure is attempting to use
336 * a key which can expire for something which can't.
337 */
338
339 int key_used(key_file *f, key *k, time_t t)
340 {
341 KEY_WRITE(f);
342 if (t == KEXP_FOREVER) {
343 if (k->exp != KEXP_FOREVER)
344 return (KERR_WILLEXPIRE);
345 } else if (k->del >= t)
346 return (0);
347
348 k->del = t;
349 KEY_MODIFY(f);
350 return (0);
351 }
352
353 /* --- @key_fingerprint@ --- *
354 *
355 * Arguments: @key *k@ = the key to fingerprint
356 * @ghash *h@ = the hash to use
357 * @const key_filter *kf@ = filter to apply
358 *
359 * Returns: Nonzero if the key slightly matched the filter.
360 *
361 * Use: Updates the hash context with the key contents.
362 */
363
364 static int abyname(const void *a, const void *b) {
365 key_attr *const *x = a, *const *y = b;
366 return (strcmp(SYM_NAME(*x), SYM_NAME(*y)));
367 }
368
369 int key_fingerprint(key *k, ghash *h, const key_filter *kf)
370 {
371 dstr d = DSTR_INIT;
372 int rc = 0;
373 key_attr *a, **v;
374 size_t n, i, len;
375 octet b[2];
376 sym_iter ai;
377
378 if (!key_encode(&k->k, &d, kf))
379 goto done;
380 rc = 1;
381 GH_HASH(h, d.buf, d.len);
382 for (n = 0, sym_mkiter(&ai, &k->a); (a = sym_next(&ai)) != 0; n++);
383 if (n) {
384 v = xmalloc(n * sizeof(*v));
385 for (i = 0, sym_mkiter(&ai, &k->a); (a = sym_next(&ai)) != 0; i++)
386 v[i] = a;
387 qsort(v, n, sizeof(*v), abyname);
388 len = strlen(k->type); STORE8(b, len);
389 GH_HASH(h, b, 1); GH_HASH(h, k->type, len);
390 for (i = 0; i < n; i++) {
391 a = v[i];
392 len = strlen(SYM_NAME(a)); STORE8(b, len);
393 GH_HASH(h, b, 1); GH_HASH(h, SYM_NAME(a), len);
394 len = strlen(a->p); STORE16(b, len);
395 GH_HASH(h, b, 2); GH_HASH(h, a->p, len);
396 }
397 xfree(v);
398 }
399 done:
400 dstr_destroy(&d);
401 return (rc);
402 }
403
404 /*----- That's all, folks -------------------------------------------------*/