b10879acc1b4cb1ffb3ada7f7fb815b2f1af8f41
[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 key_ref *kr = sym_find(&f->bytag, tag, -1, 0, 0);
164 key *k;
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 && (k = key_byid(f, id)) != 0) return (k);
170 return (key_bytype(f, tag));
171 }
172
173 /* --- @key_qtag@ --- *
174 *
175 * Arguments: @key_file *f@ = key file to find a key from
176 * @const char *tag@ = pointer to tag string
177 * @dstr *d@ = pointer to string for full tag name
178 * @key **k@ = where to store the key pointer
179 * @key_data ***kd@ = where to store the key data pointer
180 *
181 * Returns: Zero if OK, nonzero if it failed.
182 *
183 * Use: Performs a full lookup on a qualified tag name. The tag is
184 * qualified by the names of subkeys, separated by dots. Hence,
185 * a qualified tag is ID|TAG[.TAG...]. The various result
186 * pointers can be null to indicate that the result isn't
187 * interesting.
188 */
189
190 int key_qtag(key_file *f, const char *tag, dstr *d, key **k, key_data ***kd)
191 {
192 dstr dd = DSTR_INIT;
193 const char *q;
194 key *kk;
195 key_data **kkd;
196
197 /* --- Find the end of the base tag --- */
198
199 if ((q = strchr(tag, '.')) == 0)
200 DPUTS(&dd, tag);
201 else {
202 DPUTM(&dd, tag, q - tag);
203 DPUTZ(&dd);
204 q++;
205 }
206
207 /* --- Look up the key tag --- */
208
209 if ((kk = key_bytag(f, dd.buf)) == 0) {
210 dstr_destroy(&dd);
211 return (-1);
212 }
213
214 /* --- Set the various initial bits of result up --- */
215
216 if (d)
217 key_fulltag(kk, d);
218 if (k)
219 *k = kk;
220 kkd = &kk->k;
221
222 /* --- Now dig through the rest of the tag --- */
223
224 if (q) {
225 while (*q) {
226 key_struct *ks;
227
228 /* --- Stick on the next bit of the fullqtag --- */
229
230 DRESET(&dd);
231 while (*q && *q != '.') {
232 DPUTC(&dd, *q);
233 q++;
234 }
235 DPUTZ(&dd);
236 if (d) {
237 DPUTC(d, '.');
238 DPUTD(d, &dd);
239 }
240
241 /* --- Look up the subkey --- */
242
243 if ((*kkd)->e != KENC_STRUCT) {
244 kkd = 0;
245 break;
246 }
247 if ((ks = sym_find(&(*kkd)->u.s, dd.buf, -1, 0, 0)) == 0) {
248 kkd = 0;
249 break;
250 }
251 kkd = &ks->k;
252 }
253 }
254
255 /* --- Return the results --- */
256
257 dstr_destroy(&dd);
258 if (!kkd)
259 return (-1);
260 if (kd)
261 *kd = kkd;
262 return (0);
263 }
264
265 /*----- Miscellaneous functions -------------------------------------------*/
266
267 /* --- @key_delete@ --- *
268 *
269 * Arguments: @key_file *f@ = pointer to file block
270 * @key *k@ = key to delete
271 *
272 * Returns: Error code (one of the @KERR@ constants).
273 *
274 * Use: Removes the given key from the list. The key file must be
275 * writable. (Due to the horridness of the data structures,
276 * deleted keys aren't actually removed, just marked so that
277 * they can't be looked up or iterated over. One upshot of
278 * this is that they don't get written back to the file when
279 * it's closed.)
280 */
281
282 int key_delete(key_file *f, key *k)
283 {
284 KEY_WRITE(f);
285 k->exp = KEXP_EXPIRE;
286 k->del = KEXP_EXPIRE;
287 KEY_MODIFY(f);
288 return (0);
289 }
290
291 /* --- @key_expired@ --- *
292 *
293 * Arguments: @key *k@ = pointer to key block
294 *
295 * Returns: Zero if the key is OK, nonzero if it's expired.
296 */
297
298 int key_expired(key *k)
299 {
300 time_t now = time(0);
301 return (KEY_EXPIRED(now, k->exp) || KEY_EXPIRED(now, k->del));
302 }
303
304 /* --- @key_expire@ --- *
305 *
306 * Arguments: @key_file *f@ = pointer to file block
307 * @key *k@ = pointer to key block
308 *
309 * Returns: Error code (one of the @KERR@ constants).
310 *
311 * Use: Immediately marks the key as expired. It may be removed
312 * immediately, if it is no longer required, and will be removed
313 * by a tidy operation when it is no longer required. The key
314 * file must be writable.
315 */
316
317 int key_expire(key_file *f, key *k)
318 {
319 KEY_WRITE(f);
320 k->exp = KEXP_EXPIRE;
321 if (k->del == KEXP_FOREVER)
322 k->del = KEXP_EXPIRE;
323 KEY_MODIFY(f);
324 return (0);
325 }
326
327 /* --- @key_used@ --- *
328 *
329 * Arguments: @key_file *f@ = pointer to key file
330 * @key *k@ = pointer to key block
331 * @time_t t@ = when key can be removed
332 *
333 * Returns: Zero if OK, nonzero on failure.
334 *
335 * Use: Marks a key as being required until a given time. Even
336 * though the key may expire before then (and won't be returned
337 * by type after that time), it will still be available when
338 * requested explicitly by id. The key file must be writable.
339 *
340 * The only (current) reason for failure is attempting to use
341 * a key which can expire for something which can't.
342 */
343
344 int key_used(key_file *f, key *k, time_t t)
345 {
346 KEY_WRITE(f);
347 if (t == KEXP_FOREVER) {
348 if (k->exp != KEXP_FOREVER)
349 return (KERR_WILLEXPIRE);
350 } else if (k->del >= t)
351 return (0);
352
353 k->del = t;
354 KEY_MODIFY(f);
355 return (0);
356 }
357
358 /* --- @key_fingerprint@ --- *
359 *
360 * Arguments: @key *k@ = the key to fingerprint
361 * @ghash *h@ = the hash to use
362 * @const key_filter *kf@ = filter to apply
363 *
364 * Returns: Nonzero if the key slightly matched the filter.
365 *
366 * Use: Updates the hash context with the key contents.
367 */
368
369 static int abyname(const void *a, const void *b) {
370 key_attr *const *x = a, *const *y = b;
371 return (strcmp(SYM_NAME(*x), SYM_NAME(*y)));
372 }
373
374 int key_fingerprint(key *k, ghash *h, const key_filter *kf)
375 {
376 dstr d = DSTR_INIT;
377 int rc = 0;
378 key_attr *a, **v;
379 size_t n, i;
380 sym_iter ai;
381
382 if (!key_encode(k->k, &d, kf))
383 goto done;
384 rc = 1;
385 GH_HASHSTR(h, "catacomb-key-fingerprint:");
386 GH_HASHU32(h, k->id);
387 GH_HASHSTR8(h, k->type);
388 GH_HASH(h, d.buf, d.len);
389 for (n = 0, sym_mkiter(&ai, &k->a); (a = sym_next(&ai)) != 0; n++);
390 if (n) {
391 v = xmalloc(n * sizeof(*v));
392 for (i = 0, sym_mkiter(&ai, &k->a); (a = sym_next(&ai)) != 0; i++)
393 v[i] = a;
394 qsort(v, n, sizeof(*v), abyname);
395 for (i = 0; i < n; i++) {
396 GH_HASHSTR8(h, SYM_NAME(v[i]));
397 GH_HASHSTR16(h, v[i]->p);
398 }
399 xfree(v);
400 }
401 done:
402 dstr_destroy(&d);
403 return (rc);
404 }
405
406 /*----- That's all, folks -------------------------------------------------*/