Commit | Line | Data |
---|---|---|
d11a0bf7 | 1 | /* -*-c-*- |
2 | * | |
d11a0bf7 | 3 | * Simple key management |
4 | * | |
5 | * (c) 1999 Straylight/Edgeware | |
6 | */ | |
7 | ||
45c0fd36 | 8 | /*----- Licensing notice --------------------------------------------------* |
d11a0bf7 | 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. | |
45c0fd36 | 16 | * |
d11a0bf7 | 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. | |
45c0fd36 | 21 | * |
d11a0bf7 | 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 | ||
d11a0bf7 | 28 | /*----- Header files ------------------------------------------------------*/ |
29 | ||
30 | #include <stdio.h> | |
31 | #include <stdlib.h> | |
32 | #include <string.h> | |
33 | #include <time.h> | |
34 | ||
d11a0bf7 | 35 | #include <mLib/bits.h> |
36 | #include <mLib/hash.h> | |
141c1284 | 37 | #include <mLib/macros.h> |
d11a0bf7 | 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 { \ | |
b119a5eb | 46 | if (!((f)->f & KF_WRITE)) \ |
d11a0bf7 | 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 | ||
d11a0bf7 | 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; | |
f1b73d2f MW |
163 | enum { GUESS = -1, TAG, ID, TYPE }; int lookup; |
164 | key_ref *kr; | |
dd284d76 | 165 | key *k; |
d11a0bf7 | 166 | |
f1b73d2f MW |
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))) | |
d11a0bf7 | 175 | return (kr->k); |
f1b73d2f MW |
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); | |
d11a0bf7 | 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 | |
ef13e9a4 | 194 | * @key_data ***kd@ = where to store the key data pointer |
d11a0bf7 | 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 | |
ef13e9a4 | 202 | * interesting. |
d11a0bf7 | 203 | */ |
204 | ||
ef13e9a4 | 205 | int key_qtag(key_file *f, const char *tag, dstr *d, key **k, key_data ***kd) |
d11a0bf7 | 206 | { |
207 | dstr dd = DSTR_INIT; | |
208 | const char *q; | |
209 | key *kk; | |
ef13e9a4 | 210 | key_data **kkd; |
d11a0bf7 | 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 | ||
ef13e9a4 | 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; | |
d11a0bf7 | 267 | } |
d11a0bf7 | 268 | } |
269 | ||
270 | /* --- Return the results --- */ | |
271 | ||
ef13e9a4 | 272 | dstr_destroy(&dd); |
d11a0bf7 | 273 | if (!kkd) |
274 | return (-1); | |
d11a0bf7 | 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 | ||
cdb7e56a | 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 | ||
d11a0bf7 | 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 | ||
981bf127 | 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; | |
78660a58 | 394 | size_t n, i; |
981bf127 | 395 | sym_iter ai; |
396 | ||
ef13e9a4 | 397 | if (!key_encode(k->k, &d, kf)) |
981bf127 | 398 | goto done; |
399 | rc = 1; | |
78660a58 | 400 | GH_HASHSTR(h, "catacomb-key-fingerprint:"); |
401 | GH_HASHU32(h, k->id); | |
402 | GH_HASHSTR8(h, k->type); | |
981bf127 | 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); | |
981bf127 | 410 | for (i = 0; i < n; i++) { |
78660a58 | 411 | GH_HASHSTR8(h, SYM_NAME(v[i])); |
412 | GH_HASHSTR16(h, v[i]->p); | |
981bf127 | 413 | } |
414 | xfree(v); | |
45c0fd36 | 415 | } |
981bf127 | 416 | done: |
417 | dstr_destroy(&d); | |
418 | return (rc); | |
419 | } | |
420 | ||
d11a0bf7 | 421 | /*----- That's all, folks -------------------------------------------------*/ |