Commit | Line | Data |
---|---|---|
d11a0bf7 | 1 | /* -*-c-*- |
d11a0bf7 | 2 | * |
3 | * Encoding and decoding of key data | |
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 <assert.h> | |
31 | #include <stdlib.h> | |
32 | #include <string.h> | |
33 | ||
d11a0bf7 | 34 | #include <mLib/base64.h> |
35 | #include <mLib/bits.h> | |
36 | #include <mLib/dstr.h> | |
37 | #include <mLib/sub.h> | |
38 | #include <mLib/sym.h> | |
39 | ||
052b36d0 | 40 | #include "key-data.h" |
d11a0bf7 | 41 | #include "mp.h" |
42 | #include "mptext.h" | |
43 | ||
ef13e9a4 | 44 | /*----- Reference counting stuff ------------------------------------------*/ |
45 | ||
46 | /* --- @key_incref@ --- * | |
47 | * | |
48 | * Arguments: @key_data *k@ = pointer to key data | |
49 | * | |
50 | * Returns: --- | |
51 | * | |
52 | * Use: Increments the refcount on a key data block. | |
53 | */ | |
54 | ||
55 | void key_incref(key_data *k) { KEY_INCREF(k); } | |
56 | ||
57 | /* --- @key_destroy@ --- * | |
58 | * | |
59 | * Arguments: @key_data *k@ = pointer to key data to destroy | |
60 | * | |
61 | * Returns: --- | |
62 | * | |
63 | * Use: Destroys a block of key data, regardless of reference count. | |
64 | * Don't use this unless you know what you're doing. | |
65 | */ | |
66 | ||
67 | void key_destroy(key_data *k) | |
68 | { | |
69 | switch (k->e & KF_ENCMASK) { | |
70 | case KENC_BINARY: | |
71 | case KENC_ENCRYPT: | |
72 | if (k->u.k.k) { | |
73 | if (k->e & KF_BURN) | |
74 | memset(k->u.k.k, 0, k->u.k.sz); | |
75 | sub_free(k->u.k.k, k->u.k.sz); | |
76 | } | |
77 | break; | |
78 | case KENC_MP: | |
79 | mp_drop(k->u.m); | |
80 | break; | |
81 | case KENC_STRING: | |
82 | xfree(k->u.p); | |
83 | break; | |
84 | case KENC_EC: | |
85 | EC_DESTROY(&k->u.e); | |
86 | break; | |
87 | case KENC_STRUCT: { | |
88 | key_data *kd; | |
89 | key_subkeyiter i; | |
90 | ||
91 | for (key_mksubkeyiter(&i, k); key_nextsubkey(&i, 0, &kd); ) | |
92 | KEY_DROP(kd); | |
93 | sym_destroy(&k->u.s); | |
94 | } break; | |
95 | default: | |
96 | abort(); | |
97 | } | |
98 | DESTROY(k); | |
99 | } | |
100 | ||
101 | /* --- @key_drop@ --- * | |
102 | * | |
103 | * Arguments: @key_data *k@ = pointer to key data to destroy | |
104 | * | |
105 | * Returns: --- | |
106 | * | |
107 | * Use: Drops a reference to key data, destroying it if necessary. | |
108 | */ | |
109 | ||
110 | void key_drop(key_data *k) { KEY_DROP(k); } | |
111 | ||
112 | /* --- @key_split@ --- * | |
113 | * | |
114 | * Arguments: @key_data **kk@ = address of pointer to key data block | |
115 | * | |
116 | * Returns: --- | |
117 | * | |
118 | * Use: Replaces @*kk@ with a pointer to the same key data, but with | |
119 | * just one reference. | |
120 | */ | |
121 | ||
122 | void key_split(key_data **kk) | |
123 | { | |
124 | key_data *k = *kk; | |
45c0fd36 | 125 | |
ef13e9a4 | 126 | if (k->ref == 1) |
127 | return; | |
128 | switch (k->e & KF_ENCMASK) { | |
129 | case KENC_BINARY: | |
130 | *kk = key_newbinary(k->e, k->u.k.k, k->u.k.sz); | |
131 | break; | |
132 | case KENC_ENCRYPT: | |
133 | *kk = key_newencrypted(k->e, k->u.k.k, k->u.k.sz); | |
134 | break; | |
135 | case KENC_MP: | |
136 | *kk = key_newmp(k->e, k->u.m); | |
137 | break; | |
138 | case KENC_STRING: | |
139 | *kk = key_newstring(k->e, k->u.p); | |
140 | break; | |
141 | case KENC_EC: | |
142 | *kk = key_newec(k->e, &k->u.e); | |
143 | break; | |
144 | case KENC_STRUCT: { | |
145 | key_subkeyiter i; | |
146 | const char *tag; | |
147 | key_data *kd; | |
148 | ||
149 | *kk = key_newstruct(); | |
150 | for (key_mksubkeyiter(&i, k); key_nextsubkey(&i, &tag, &kd); ) | |
151 | key_structset(*kk, tag, kd); | |
152 | } break; | |
153 | default: | |
154 | abort(); | |
155 | } | |
156 | } | |
157 | ||
d11a0bf7 | 158 | /*----- Setting new values ------------------------------------------------*/ |
159 | ||
ef13e9a4 | 160 | /* --- @key_newraw@ --- * |
d11a0bf7 | 161 | * |
ef13e9a4 | 162 | * Arguments: @unsigned e@ = encoding type to set |
163 | * | |
164 | * Returns: New key block, not filled in. | |
165 | */ | |
166 | ||
167 | key_data *key_newraw(unsigned e) | |
168 | { | |
169 | key_data *k = CREATE(key_data); | |
170 | k->e = e; | |
171 | k->ref = 1; | |
172 | return (k); | |
173 | } | |
174 | ||
175 | /* --- @key_newbinary@ --- * | |
176 | * | |
177 | * Arguments: @unsigned e@ = other encoding flags | |
d11a0bf7 | 178 | * @const void *p@ = pointer to key data |
179 | * @size_t sz@ = size of the key data | |
180 | * | |
ef13e9a4 | 181 | * Returns: New key data object. |
d11a0bf7 | 182 | */ |
183 | ||
ef13e9a4 | 184 | key_data *key_newbinary(unsigned e, const void *p, size_t sz) |
d11a0bf7 | 185 | { |
ef13e9a4 | 186 | key_data *k = key_newraw(KENC_BINARY | e); |
d11a0bf7 | 187 | k->u.k.k = sub_alloc(sz); |
188 | memcpy(k->u.k.k, p, sz); | |
189 | k->u.k.sz = sz; | |
ef13e9a4 | 190 | return (k); |
d11a0bf7 | 191 | } |
192 | ||
ef13e9a4 | 193 | /* --- @key_newencrypted@ --- * |
d11a0bf7 | 194 | * |
ef13e9a4 | 195 | * Arguments: @unsigned e@ = other encoding flags |
d11a0bf7 | 196 | * @const void *p@ = pointer to key data |
197 | * @size_t sz@ = size of the key data | |
198 | * | |
ef13e9a4 | 199 | * Returns: New key data object. |
d11a0bf7 | 200 | */ |
201 | ||
ef13e9a4 | 202 | key_data *key_newencrypted(unsigned e, const void *p, size_t sz) |
d11a0bf7 | 203 | { |
ef13e9a4 | 204 | key_data *k = key_newraw(KENC_ENCRYPT | e); |
d11a0bf7 | 205 | k->u.k.k = sub_alloc(sz); |
206 | memcpy(k->u.k.k, p, sz); | |
207 | k->u.k.sz = sz; | |
ef13e9a4 | 208 | return (k); |
d11a0bf7 | 209 | } |
210 | ||
4e28b711 | 211 | /* --- @key_newmp@ --- * |
d11a0bf7 | 212 | * |
ef13e9a4 | 213 | * Arguments: @unsigned e@ = other encoding flags |
d11a0bf7 | 214 | * @mp *m@ = pointer to the value to set |
215 | * | |
ef13e9a4 | 216 | * Returns: New key data object. |
d11a0bf7 | 217 | */ |
218 | ||
ef13e9a4 | 219 | key_data *key_newmp(unsigned e, mp *m) |
d11a0bf7 | 220 | { |
ef13e9a4 | 221 | key_data *k = key_newraw(KENC_MP | e); |
d11a0bf7 | 222 | k->u.m = MP_COPY(m); |
ef13e9a4 | 223 | return (k); |
d11a0bf7 | 224 | } |
225 | ||
ef13e9a4 | 226 | /* --- @key_newstring@ --- * |
1ba83484 | 227 | * |
ef13e9a4 | 228 | * Arguments: @unsigned e@ = other encoding flags |
1ba83484 | 229 | * @const char *p@ = pointer to the value to set |
230 | * | |
ef13e9a4 | 231 | * Returns: New key data object. |
1ba83484 | 232 | */ |
233 | ||
ef13e9a4 | 234 | key_data *key_newstring(unsigned e, const char *p) |
1ba83484 | 235 | { |
ef13e9a4 | 236 | key_data *k = key_newraw(KENC_STRING | e); |
1ba83484 | 237 | k->u.p = xstrdup(p); |
ef13e9a4 | 238 | return (k); |
1ba83484 | 239 | } |
240 | ||
ef13e9a4 | 241 | /* --- @key_newec@ --- * |
1ba83484 | 242 | * |
ef13e9a4 | 243 | * Arguments: @unsigned e@ = other encoding flags |
244 | * @const ec *pt@ = pointer to the value to set | |
1ba83484 | 245 | * |
ef13e9a4 | 246 | * Returns: New key data object. |
1ba83484 | 247 | */ |
248 | ||
ef13e9a4 | 249 | key_data *key_newec(unsigned e, const ec *pt) |
250 | { | |
251 | key_data *k = key_newraw(KENC_EC | e); | |
1ba83484 | 252 | EC_CREATE(&k->u.e); |
ef13e9a4 | 253 | EC_COPY(&k->u.e, pt); |
254 | return (k); | |
1ba83484 | 255 | } |
256 | ||
ef13e9a4 | 257 | /* --- @key_newstruct@ --- * |
d11a0bf7 | 258 | * |
ef13e9a4 | 259 | * Arguments: --- |
d11a0bf7 | 260 | * |
ef13e9a4 | 261 | * Returns: New key data object. |
d11a0bf7 | 262 | */ |
263 | ||
ef13e9a4 | 264 | key_data *key_newstruct(void) |
d11a0bf7 | 265 | { |
ef13e9a4 | 266 | key_data *k = key_newraw(KENC_STRUCT); |
d11a0bf7 | 267 | sym_create(&k->u.s); |
ef13e9a4 | 268 | return (k); |
d11a0bf7 | 269 | } |
270 | ||
271 | /* --- @key_structfind@ --- * | |
272 | * | |
273 | * Arguments: @key_data *k@ = pointer to key data block | |
274 | * @const char *tag@ = pointer to tag string | |
275 | * | |
276 | * Returns: Pointer to key data block, or null. | |
277 | * | |
278 | * Use: Looks up the tag in a structured key. | |
279 | */ | |
280 | ||
281 | key_data *key_structfind(key_data *k, const char *tag) | |
282 | { | |
283 | key_struct *ks; | |
380a6fdc | 284 | assert(((void)"Key is not structured", |
285 | (k->e & KF_ENCMASK) == KENC_STRUCT)); | |
d11a0bf7 | 286 | ks = sym_find(&k->u.s, tag, -1, 0, 0); |
380a6fdc | 287 | if (!ks) |
288 | return (0); | |
ef13e9a4 | 289 | return (ks->k); |
d11a0bf7 | 290 | } |
291 | ||
ef13e9a4 | 292 | /* --- @key_mksubkeyiter@ --- * |
d11a0bf7 | 293 | * |
ef13e9a4 | 294 | * Arguments: @key_subkeyiter *i@ = pointer to iterator block |
295 | * @key_data *k@ = pointer to key data block | |
296 | * | |
297 | * Returns: --- | |
298 | * | |
299 | * Use: Initializes a subkey iterator. | |
300 | */ | |
301 | ||
302 | void key_mksubkeyiter(key_subkeyiter *i, key_data *k) | |
303 | { | |
304 | assert(((void)"Key is not structured", | |
305 | (k->e & KF_ENCMASK) == KENC_STRUCT)); | |
306 | sym_mkiter(&i->i, &k->u.s); | |
307 | } | |
308 | ||
309 | /* --- @key_nextsubkey@ --- * | |
d11a0bf7 | 310 | * |
ef13e9a4 | 311 | * Arguments: @key_structiter *i@ = pointer to iterator block |
312 | * @const char **tag@ = where to put the tag pointer, or null | |
313 | * @key_data **kd@ = where to put the key data pointer, or null | |
d11a0bf7 | 314 | * |
ef13e9a4 | 315 | * Returns: Nonzero if there was another item, zero if we hit the |
316 | * end-stop. | |
317 | * | |
318 | * Use: Collects the next subkey of a structured key. | |
d11a0bf7 | 319 | */ |
320 | ||
ef13e9a4 | 321 | int key_nextsubkey(key_subkeyiter *i, const char **tag, key_data **kd) |
d11a0bf7 | 322 | { |
323 | key_struct *ks; | |
d11a0bf7 | 324 | |
ef13e9a4 | 325 | if ((ks = sym_next(&i->i)) == 0) |
326 | return (0); | |
327 | if (tag) *tag = SYM_NAME(ks); | |
328 | if (kd) *kd = ks->k; | |
78ec50fa | 329 | return (1); |
d11a0bf7 | 330 | } |
331 | ||
ef13e9a4 | 332 | /* --- @key_structset@, @key_structsteal@ --- * |
d11a0bf7 | 333 | * |
ef13e9a4 | 334 | * Arguments: @key_data *k@ = pointer to key data block |
335 | * @const char *tag@ = pointer to tag string | |
336 | * @key_data *kd@ = new key data to store | |
d11a0bf7 | 337 | * |
052b36d0 | 338 | * Returns: --- |
d11a0bf7 | 339 | * |
ef13e9a4 | 340 | * Use: Creates a new subkey. Stealing doesn't affect @kd@'s |
341 | * refcount. If @kd@ is null, the subkey is deleted. | |
d11a0bf7 | 342 | */ |
343 | ||
ef13e9a4 | 344 | static void structset(key_data *k, int stealp, |
345 | const char *tag, key_data *kd) | |
d11a0bf7 | 346 | { |
ef13e9a4 | 347 | key_struct *ks; |
348 | unsigned f; | |
d11a0bf7 | 349 | |
ef13e9a4 | 350 | assert(((void)"Key is not structured", k->e == KENC_STRUCT)); |
a6864ad9 | 351 | assert(((void)"Key has multiple references", k->ref == 1)); |
ef13e9a4 | 352 | if (!kd) { |
353 | ks = sym_find(&k->u.s, tag, -1, 0, 0); | |
354 | if (ks) sym_remove(&k->u.s, ks); | |
355 | } else { | |
356 | ks = sym_find(&k->u.s, tag, -1, sizeof(*ks), &f); | |
357 | if (f) | |
358 | key_drop(ks->k); | |
359 | if (!stealp) KEY_INCREF(kd); | |
360 | ks->k = kd; | |
45c0fd36 | 361 | } |
d11a0bf7 | 362 | } |
363 | ||
ef13e9a4 | 364 | void key_structset(key_data *k, const char *tag, key_data *kd) |
365 | { structset(k, 0, tag, kd); } | |
366 | void key_structsteal(key_data *k, const char *tag, key_data *kd) | |
367 | { structset(k, 1, tag, kd); } | |
368 | ||
369 | /*----- Miscellaneous operations ------------------------------------------*/ | |
370 | ||
d11a0bf7 | 371 | /* --- @key_do@ --- * |
372 | * | |
373 | * Arguments: @key_data *k@ = pointer to key data block | |
374 | * @const key_filter *kf@ = pointer to filter block | |
375 | * @dstr *d@ = pointer to base string | |
376 | * @int (*func)(key_data *kd, dstr *d, void *p@ = function | |
377 | * @void *p@ = argument to function | |
378 | * | |
379 | * Returns: Nonzero return code from function, or zero. | |
380 | * | |
45c0fd36 | 381 | * Use: Runs a function over all the leaves of a key. |
d11a0bf7 | 382 | */ |
383 | ||
384 | int key_do(key_data *k, const key_filter *kf, dstr *d, | |
385 | int (*func)(key_data */*kd*/, dstr */*d*/, void */*p*/), | |
386 | void *p) | |
387 | { | |
388 | if (!KEY_MATCH(k, kf)) | |
389 | return (0); | |
390 | if ((k->e & KF_ENCMASK) != KENC_STRUCT) | |
391 | return (func(k, d, p)); | |
392 | else { | |
ef13e9a4 | 393 | key_subkeyiter i; |
394 | const char *tag; | |
2cc51ff1 | 395 | size_t n = 0; |
d11a0bf7 | 396 | int rc; |
397 | ||
398 | if (d) | |
399 | n = d->len; | |
ef13e9a4 | 400 | for (key_mksubkeyiter(&i, k); key_nextsubkey(&i, &tag, &k); ) { |
d11a0bf7 | 401 | if (d) { |
402 | d->len = n; | |
ef13e9a4 | 403 | dstr_putf(d, ".%s", tag); |
d11a0bf7 | 404 | } |
ef13e9a4 | 405 | if ((rc = key_do(k, kf, d, func, p)) != 0) |
d11a0bf7 | 406 | return (rc); |
407 | } | |
408 | return (0); | |
409 | } | |
410 | } | |
411 | ||
6a7dce91 MW |
412 | /* --- @key_copydata@ --- * |
413 | * | |
414 | * Arguments: @key_data *k@ = key data to copy | |
415 | * @const key_filter *kf@ = pointer to filter block | |
416 | * | |
417 | * Returns: Pointer to a copy of the data, or null if the root subkey | |
418 | * didn't match the filter. | |
419 | * | |
420 | * Use: Copies a chunk of key data. Subkeys, whether they're | |
421 | * structured or leaves, which don't match the filter aren't | |
422 | * copied. The copy may or may not have structure in common | |
423 | * with the original. | |
424 | */ | |
425 | ||
426 | static int structmatchp(key_data *k, const key_filter *kf) | |
427 | { | |
428 | key_subkeyiter i; | |
429 | ||
430 | if (!KEY_MATCH(k, kf)) return (0); | |
431 | else if ((k->e & KF_ENCMASK) == KENC_STRUCT) return (1); | |
432 | else { | |
433 | for (key_mksubkeyiter(&i, k); key_nextsubkey(&i, 0, &k); ) | |
434 | if (!structmatchp(k, kf)) return (0); | |
435 | return (1); | |
436 | } | |
437 | } | |
438 | ||
439 | key_data *key_copydata(key_data *k, const key_filter *kf) | |
440 | { | |
441 | key_subkeyiter i; | |
442 | const char *tag; | |
443 | key_data *kd, *kkd; | |
444 | ||
445 | /* --- Trivial cases --- */ | |
446 | ||
447 | if (!KEY_MATCH(k, kf)) | |
448 | return (0); | |
449 | else if (structmatchp(k, kf)) { | |
450 | key_incref(k); | |
451 | return (k); | |
452 | } | |
453 | ||
454 | /* --- Copy a structured key recursively --- */ | |
455 | ||
456 | kkd = key_newstruct(); | |
457 | for (key_mksubkeyiter(&i, k); key_nextsubkey(&i, &tag, &kd); ) { | |
458 | if ((kd = key_copydata(kd, kf)) != 0) | |
459 | key_structsteal(kkd, tag, kd); | |
460 | } | |
461 | ||
462 | /* --- Done --- */ | |
463 | ||
464 | return (kkd); | |
465 | } | |
466 | ||
d11a0bf7 | 467 | /*----- That's all, folks -------------------------------------------------*/ |