Indentation fix.
[u/mdw/catacomb] / key-misc.c
1 /* -*-c-*-
2 *
3 * $Id: key-misc.c,v 1.3 2001/06/22 19:39:12 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 /*----- Revision history --------------------------------------------------*
31 *
32 * $Log: key-misc.c,v $
33 * Revision 1.3 2001/06/22 19:39:12 mdw
34 * New interface to find out whether a key has expired. Also, a bug fix
35 * to @key_bytag@ so that it finds expired keys correctly.
36 *
37 * Revision 1.2 2000/02/12 18:21:02 mdw
38 * Overhaul of key management (again).
39 *
40 * Revision 1.1 1999/12/22 15:47:48 mdw
41 * Major key-management revision.
42 *
43 */
44
45 /*----- Header files ------------------------------------------------------*/
46
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <time.h>
51
52 #include <mLib/bits.h>
53 #include <mLib/hash.h>
54 #include <mLib/sub.h>
55 #include <mLib/sym.h>
56
57 #include "key.h"
58
59 /*----- Useful macros -----------------------------------------------------*/
60
61 #define KEY_WRITE(f) do { \
62 if (!(f)->f & KF_WRITE) \
63 return (KERR_READONLY); \
64 } while (0)
65
66 #define KEY_MODIFY(f) do { (f)->f |= KF_MODIFIED; } while (0)
67
68 #define KEY_LOAD(n) ((n) * 2)
69
70 /*----- Iteration and iterators -------------------------------------------*/
71
72 /* --- @key_mkiter@ --- *
73 *
74 * Arguments: @key_iter *i@ = pointer to iterator object
75 * @key_file *f@ = pointer to file structure
76 *
77 * Returns: ---
78 *
79 * Use: Initializes a key iterator. The keys are returned by
80 * @key_next@.
81 */
82
83 void key_mkiter(key_iter *i, key_file *f)
84 {
85 HASH_MKITER(&i->i, &f->byid);
86 i->t = time(0);
87 }
88
89 /* --- @key_next@ --- *
90 *
91 * Arguments: @key_iter *i@ = pointer to iterator object
92 *
93 * Returns: Pointer to next key, or null.
94 *
95 * Use: Returns the next key in some arbitrary sequence.
96 */
97
98 key *key_next(key_iter *i)
99 {
100 hash_base *b;
101 key *k;
102 do {
103 HASH_NEXT(&i->i, b);
104 k = (key *)b;
105 } while (k && KEY_EXPIRED(i->t, k->exp) && KEY_EXPIRED(i->t, k->del));
106 return (k);
107 }
108
109 /*----- Lookup ------------------------------------------------------------*/
110
111 /* --- @key_bytype@ --- *
112 *
113 * Arguments: @key_file *f@ = key file we want a key from
114 * @const char *type@ = type string for desired key
115 *
116 * Returns: Pointer to the best key to use, or null.
117 *
118 * Use: Looks up a key by its type. Returns the key with the latest
119 * expiry time. This function will not return an expired key.
120 */
121
122 key *key_bytype(key_file *f, const char *type)
123 {
124 time_t now = time(0);
125 key *k;
126 key_ref *kr;
127
128 if ((kr = sym_find(&f->bytype, type, -1, 0, 0)) == 0)
129 return (0);
130 for (k = kr->k; k && KEY_EXPIRED(now, k->exp); k = k->next)
131 ;
132 return (k);
133 }
134
135 /* --- @key_byid@ --- *
136 *
137 * Arguments: @key_file *f@ = key file to find a key from
138 * @uint32 id@ = id to look for
139 *
140 * Returns: Key with matching id.
141 *
142 * Use: Returns a key given its id. This function will return an
143 * expired key, but not a deleted one.
144 */
145
146 key *key_byid(key_file *f, uint32 id)
147 {
148 time_t t = time(0);
149 hash_base **bin, *b;
150
151 bin = HASH_BIN(&f->byid, id);
152 for (b = *bin; b; b = b->next) {
153 if (b->hash == id) {
154 key *k = (key *)b;
155 if (KEY_EXPIRED(t, k->exp) && KEY_EXPIRED(t, k->del))
156 return (0);
157 return (k);
158 }
159 }
160 return (0);
161 }
162
163 /* --- @key_bytag@ --- *
164 *
165 * Arguments: @key_file *f@ = key file to find a key from
166 * @const char *tag@ = pointer to tag string
167 *
168 * Returns: Key with matching id or tag.
169 *
170 * Use: Returns a key given its tag or id. This function will return
171 * an expired key, but not a deleted one.
172 */
173
174 key *key_bytag(key_file *f, const char *tag)
175 {
176 time_t t = time(0);
177 char *p;
178 uint32 id;
179 key_ref *kr = sym_find(&f->bytag, tag, -1, 0, 0);
180
181 if (kr && !(KEY_EXPIRED(t, kr->k->exp) && KEY_EXPIRED(t, kr->k->del)))
182 return (kr->k);
183 id = strtoul(tag, &p, 16);
184 if (!*p)
185 return (key_byid(f, id));
186 return (key_bytype(f, tag));
187 }
188
189 /* --- @key_qtag@ --- *
190 *
191 * Arguments: @key_file *f@ = key file to find a key from
192 * @const char *tag@ = pointer to tag string
193 * @dstr *d@ = pointer to string for full tag name
194 * @key **k@ = where to store the key pointer
195 * @key_data **kd@ = where to store the key data pointer
196 *
197 * Returns: Zero if OK, nonzero if it failed.
198 *
199 * Use: Performs a full lookup on a qualified tag name. The tag is
200 * qualified by the names of subkeys, separated by dots. Hence,
201 * a qualified tag is ID|TAG[.TAG...]. The various result
202 * pointers can be null to indicate that the result isn't
203 * interesting.
204 */
205
206 int key_qtag(key_file *f, const char *tag, dstr *d, key **k, key_data **kd)
207 {
208 dstr dd = DSTR_INIT;
209 const char *q;
210 key *kk;
211 key_data *kkd;
212
213 /* --- Find the end of the base tag --- */
214
215 if ((q = strchr(tag, '.')) == 0)
216 DPUTS(&dd, tag);
217 else {
218 DPUTM(&dd, tag, q - tag);
219 DPUTZ(&dd);
220 q++;
221 }
222
223 /* --- Look up the key tag --- */
224
225 if ((kk = key_bytag(f, dd.buf)) == 0) {
226 dstr_destroy(&dd);
227 return (-1);
228 }
229
230 /* --- Set the various initial bits of result up --- */
231
232 if (d)
233 key_fulltag(kk, d);
234 if (k)
235 *k = kk;
236 kkd = &kk->k;
237
238 /* --- Now dig through the rest of the tag --- */
239
240 while (q && *q) {
241
242 /* --- Stick on the next bit of the fullqtag --- */
243
244 DRESET(&dd);
245 while (*q && *q != '.') {
246 DPUTC(&dd, *q);
247 q++;
248 }
249 DPUTZ(&dd);
250 if (d) {
251 DPUTC(d, '.');
252 DPUTD(d, &dd);
253 }
254
255 /* --- Look up the subkey --- */
256
257 if (kkd->e != KENC_STRUCT) {
258 kkd = 0;
259 break;
260 }
261 if ((kkd = key_structfind(kkd, dd.buf)) == 0)
262 break;
263 }
264
265 /* --- Return the results --- */
266
267 if (!kkd)
268 return (-1);
269 dstr_destroy(&dd);
270 if (kd)
271 *kd = kkd;
272 return (0);
273 }
274
275 /*----- Miscellaneous functions -------------------------------------------*/
276
277 /* --- @key_delete@ --- *
278 *
279 * Arguments: @key_file *f@ = pointer to file block
280 * @key *k@ = key to delete
281 *
282 * Returns: Error code (one of the @KERR@ constants).
283 *
284 * Use: Removes the given key from the list. The key file must be
285 * writable. (Due to the horridness of the data structures,
286 * deleted keys aren't actually removed, just marked so that
287 * they can't be looked up or iterated over. One upshot of
288 * this is that they don't get written back to the file when
289 * it's closed.)
290 */
291
292 int key_delete(key_file *f, key *k)
293 {
294 KEY_WRITE(f);
295 k->exp = KEXP_EXPIRE;
296 k->del = KEXP_EXPIRE;
297 KEY_MODIFY(f);
298 return (0);
299 }
300
301 /* --- @key_expired@ --- *
302 *
303 * Arguments: @key *k@ = pointer to key block
304 *
305 * Returns: Zero if the key is OK, nonzero if it's expired.
306 */
307
308 int key_expired(key *k)
309 {
310 time_t now = time(0);
311 return (KEY_EXPIRED(now, k->exp) || KEY_EXPIRED(now, k->del));
312 }
313
314 /* --- @key_expire@ --- *
315 *
316 * Arguments: @key_file *f@ = pointer to file block
317 * @key *k@ = pointer to key block
318 *
319 * Returns: Error code (one of the @KERR@ constants).
320 *
321 * Use: Immediately marks the key as expired. It may be removed
322 * immediately, if it is no longer required, and will be removed
323 * by a tidy operation when it is no longer required. The key
324 * file must be writable.
325 */
326
327 int key_expire(key_file *f, key *k)
328 {
329 KEY_WRITE(f);
330 k->exp = KEXP_EXPIRE;
331 if (k->del == KEXP_FOREVER)
332 k->del = KEXP_EXPIRE;
333 KEY_MODIFY(f);
334 return (0);
335 }
336
337 /* --- @key_used@ --- *
338 *
339 * Arguments: @key_file *f@ = pointer to key file
340 * @key *k@ = pointer to key block
341 * @time_t t@ = when key can be removed
342 *
343 * Returns: Zero if OK, nonzero on failure.
344 *
345 * Use: Marks a key as being required until a given time. Even
346 * though the key may expire before then (and won't be returned
347 * by type after that time), it will still be available when
348 * requested explicitly by id. The key file must be writable.
349 *
350 * The only (current) reason for failure is attempting to use
351 * a key which can expire for something which can't.
352 */
353
354 int key_used(key_file *f, key *k, time_t t)
355 {
356 KEY_WRITE(f);
357 if (t == KEXP_FOREVER) {
358 if (k->exp != KEXP_FOREVER)
359 return (KERR_WILLEXPIRE);
360 } else if (k->del >= t)
361 return (0);
362
363 k->del = t;
364 KEY_MODIFY(f);
365 return (0);
366 }
367
368 /*----- That's all, folks -------------------------------------------------*/