3 * Simple key management
5 * (c) 1999 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of Catacomb.
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.
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.
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,
28 /*----- Header files ------------------------------------------------------*/
35 #include <mLib/bits.h>
36 #include <mLib/hash.h>
37 #include <mLib/macros.h>
43 /*----- Useful macros -----------------------------------------------------*/
45 #define KEY_WRITE(f) do { \
46 if (!((f)->f & KF_WRITE)) \
47 return (KERR_READONLY); \
50 #define KEY_MODIFY(f) do { (f)->f |= KF_MODIFIED; } while (0)
52 #define KEY_LOAD(n) ((n) * 2)
54 /*----- Iteration and iterators -------------------------------------------*/
56 /* --- @key_mkiter@ --- *
58 * Arguments: @key_iter *i@ = pointer to iterator object
59 * @key_file *f@ = pointer to file structure
63 * Use: Initializes a key iterator. The keys are returned by
67 void key_mkiter(key_iter *i, key_file *f)
69 HASH_MKITER(&i->i, &f->byid);
73 /* --- @key_next@ --- *
75 * Arguments: @key_iter *i@ = pointer to iterator object
77 * Returns: Pointer to next key, or null.
79 * Use: Returns the next key in some arbitrary sequence.
82 key *key_next(key_iter *i)
89 } while (k && KEY_EXPIRED(i->t, k->exp) && KEY_EXPIRED(i->t, k->del));
93 /*----- Lookup ------------------------------------------------------------*/
95 /* --- @key_bytype@ --- *
97 * Arguments: @key_file *f@ = key file we want a key from
98 * @const char *type@ = type string for desired key
100 * Returns: Pointer to the best key to use, or null.
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.
106 key *key_bytype(key_file *f, const char *type)
108 time_t now = time(0);
112 if ((kr = sym_find(&f->bytype, type, -1, 0, 0)) == 0)
114 for (k = kr->k; k && KEY_EXPIRED(now, k->exp); k = k->next)
119 /* --- @key_byid@ --- *
121 * Arguments: @key_file *f@ = key file to find a key from
122 * @uint32 id@ = id to look for
124 * Returns: Key with matching id.
126 * Use: Returns a key given its id. This function will return an
127 * expired key, but not a deleted one.
130 key *key_byid(key_file *f, uint32 id)
135 bin = HASH_BIN(&f->byid, id);
136 for (b = *bin; b; b = b->next) {
139 if (KEY_EXPIRED(t, k->exp) && KEY_EXPIRED(t, k->del))
147 /* --- @key_bytag@ --- *
149 * Arguments: @key_file *f@ = key file to find a key from
150 * @const char *tag@ = pointer to tag string
152 * Returns: Key with matching id or tag.
154 * Use: Returns a key given its tag or id. This function will return
155 * an expired key, but not a deleted one.
158 key *key_bytag(key_file *f, const char *tag)
163 enum { GUESS = -1, TAG, ID, TYPE }; int lookup;
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; }
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)))
177 if (lookup == GUESS || lookup == ID) {
178 id = strtoul(tag, &p, 16);
179 if (!*p && (k = key_byid(f, id)) != 0) return (k);
182 if ((lookup == GUESS || lookup == TYPE) && (k = key_bytype(f, tag)) != 0)
188 /* --- @key_qtag@ --- *
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
194 * @key_data ***kd@ = where to store the key data pointer
196 * Returns: Zero if OK, nonzero if it failed.
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
205 int key_qtag(key_file *f, const char *tag, dstr *d, key **k, key_data ***kd)
212 /* --- Find the end of the base tag --- */
214 if ((q = strchr(tag, '.')) == 0)
217 DPUTM(&dd, tag, q - tag);
222 /* --- Look up the key tag --- */
224 if ((kk = key_bytag(f, dd.buf)) == 0) {
229 /* --- Set the various initial bits of result up --- */
237 /* --- Now dig through the rest of the tag --- */
243 /* --- Stick on the next bit of the fullqtag --- */
246 while (*q && *q != '.') {
256 /* --- Look up the subkey --- */
258 if ((*kkd)->e != KENC_STRUCT) {
262 if ((ks = sym_find(&(*kkd)->u.s, dd.buf, -1, 0, 0)) == 0) {
270 /* --- Return the results --- */
280 /*----- Miscellaneous functions -------------------------------------------*/
282 /* --- @key_delete@ --- *
284 * Arguments: @key_file *f@ = pointer to file block
285 * @key *k@ = key to delete
287 * Returns: Error code (one of the @KERR@ constants).
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
297 int key_delete(key_file *f, key *k)
300 k->exp = KEXP_EXPIRE;
301 k->del = KEXP_EXPIRE;
306 /* --- @key_expired@ --- *
308 * Arguments: @key *k@ = pointer to key block
310 * Returns: Zero if the key is OK, nonzero if it's expired.
313 int key_expired(key *k)
315 time_t now = time(0);
316 return (KEY_EXPIRED(now, k->exp) || KEY_EXPIRED(now, k->del));
319 /* --- @key_expire@ --- *
321 * Arguments: @key_file *f@ = pointer to file block
322 * @key *k@ = pointer to key block
324 * Returns: Error code (one of the @KERR@ constants).
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.
332 int key_expire(key_file *f, key *k)
335 k->exp = KEXP_EXPIRE;
336 if (k->del == KEXP_FOREVER)
337 k->del = KEXP_EXPIRE;
342 /* --- @key_used@ --- *
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
348 * Returns: Zero if OK, nonzero on failure.
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.
355 * The only (current) reason for failure is attempting to use
356 * a key which can expire for something which can't.
359 int key_used(key_file *f, key *k, time_t t)
362 if (t == KEXP_FOREVER) {
363 if (k->exp != KEXP_FOREVER)
364 return (KERR_WILLEXPIRE);
365 } else if (k->del >= t)
373 /* --- @key_fingerprint@ --- *
375 * Arguments: @key *k@ = the key to fingerprint
376 * @ghash *h@ = the hash to use
377 * @const key_filter *kf@ = filter to apply
379 * Returns: Nonzero if the key slightly matched the filter.
381 * Use: Updates the hash context with the key contents.
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)));
389 int key_fingerprint(key *k, ghash *h, const key_filter *kf)
397 if (!key_encode(k->k, &d, kf))
400 GH_HASHSTR(h, "catacomb-key-fingerprint:");
401 GH_HASHU32(h, k->id);
402 GH_HASHSTR8(h, k->type);
403 GH_HASH(h, d.buf, d.len);
404 for (n = 0, sym_mkiter(&ai, &k->a); (a = sym_next(&ai)) != 0; n++);
406 v = xmalloc(n * sizeof(*v));
407 for (i = 0, sym_mkiter(&ai, &k->a); (a = sym_next(&ai)) != 0; i++)
409 qsort(v, n, sizeof(*v), abyname);
410 for (i = 0; i < n; i++) {
411 GH_HASHSTR8(h, SYM_NAME(v[i]));
412 GH_HASHSTR16(h, v[i]->p);
421 /*----- That's all, folks -------------------------------------------------*/