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