server/keymgmt.c (kh_reopen): Promote the happy path.
[tripe] / server / keymgmt.c
CommitLineData
410c8acf 1/* -*-c-*-
2 *
410c8acf 3 * Key loading and storing
4 *
5 * (c) 2001 Straylight/Edgeware
6 */
7
e04c2d50 8/*----- Licensing notice --------------------------------------------------*
410c8acf 9 *
10 * This file is part of Trivial IP Encryption (TrIPE).
11 *
11ad66c2
MW
12 * TrIPE is free software: you can redistribute it and/or modify it under
13 * the terms of the GNU General Public License as published by the Free
14 * Software Foundation; either version 3 of the License, or (at your
15 * option) any later version.
e04c2d50 16 *
11ad66c2
MW
17 * TrIPE is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
e04c2d50 21 *
410c8acf 22 * You should have received a copy of the GNU General Public License
11ad66c2 23 * along with TrIPE. If not, see <https://www.gnu.org/licenses/>.
410c8acf 24 */
25
410c8acf 26/*----- Header files ------------------------------------------------------*/
27
28#include "tripe.h"
29
b5c45da1 30/*----- Algswitch stuff ---------------------------------------------------*/
31
32/* --- @algs_get@ --- *
33 *
34 * Arguments: @algswitch *a@ = where to put the algorithms
4998da61 35 * @dstr *e@ = where to write error tokens
4d36660a 36 * @key_file *kf@ = key file
b5c45da1 37 * @key *k@ = key to inspect
38 *
4d36660a 39 * Returns: Zero if OK; nonzero on error.
b5c45da1 40 *
41 * Use: Extracts an algorithm choice from a key.
42 */
43
4d36660a 44static int algs_get(algswitch *a, dstr *e, key_file *kf, key *k)
b5c45da1 45{
46 const char *p;
c70a7c5c 47 const bulkops *bops;
b87bffcb 48 dstr d = DSTR_INIT, dd = DSTR_INIT;
4d36660a 49 int rc = -1;
b5c45da1 50
4d36660a
MW
51 /* --- Hash function --- */
52
53 if ((p = key_getattr(kf, k, "hash")) == 0) p = "rmd160";
54 if ((a->h = ghash_byname(p)) == 0) {
55 a_format(e, "unknown-hash", "%s", p, A_END);
56 goto done;
57 }
b5c45da1 58
4d36660a 59 /* --- Symmetric encryption for key derivation --- */
b5c45da1 60
74ee77cb 61 if ((p = key_getattr(kf, k, "mgf")) == 0) {
b5c45da1 62 dstr_reset(&d);
74ee77cb 63 dstr_putf(&d, "%s-mgf", a->h->name);
b5c45da1 64 p = d.buf;
65 }
4d36660a
MW
66 if ((a->mgf = gcipher_byname(p)) == 0) {
67 a_format(e, "unknown-mgf-cipher", "%s", p, A_END);
68 goto done;
69 }
70
a93aacce 71 /* --- Bulk crypto transform --- */
b5c45da1 72
a93aacce 73 if ((p = key_getattr(kf, k, "bulk")) == 0) p = "v0";
c70a7c5c
MW
74 for (bops = bulktab; bops->name && strcmp(p, bops->name) != 0; bops++);
75 if (!bops->name) {
a93aacce
MW
76 a_format(e, "unknown-bulk-transform", "%s", p, A_END);
77 goto done;
78 }
c70a7c5c
MW
79 if ((a->bulk = bops->getalgs(a, e, kf, k)) == 0) goto done;
80 a->bulk->ops = bops;
b5c45da1 81
a93aacce
MW
82 /* --- All done --- */
83
4d36660a 84 rc = 0;
b5c45da1 85done:
86 dstr_destroy(&d);
b87bffcb 87 dstr_destroy(&dd);
4d36660a 88 return (rc);
b5c45da1 89}
90
91/* --- @algs_check@ --- *
92 *
93 * Arguments: @algswitch *a@ = a choice of algorithms
4d36660a 94 * @dstr *e@ = where to write error tokens
5b9f3d37 95 * @const dhgrp *grp@ = the group we're working in
b5c45da1 96 *
4d36660a 97 * Returns: Zero if OK; nonzero on error.
b5c45da1 98 *
99 * Use: Checks an algorithm choice for sensibleness. This also
100 * derives some useful information from the choices, and you
101 * must call this before committing the algorithm selection
102 * for use by @keyset@ functions.
103 */
104
5b9f3d37 105static int algs_check(algswitch *a, dstr *e, const dhgrp *grp)
b5c45da1 106{
b5c45da1 107 a->hashsz = a->h->hashsz;
b5c45da1 108
4d36660a
MW
109 if (keysz(a->hashsz, a->mgf->keysz) != a->hashsz) {
110 a_format(e, "mgf", "%s", a->mgf->name,
111 "restrictive-key-schedule",
112 A_END);
113 return (-1);
114 }
b5c45da1 115
c70a7c5c 116 if (a->bulk->ops->checkalgs(a->bulk, a, e)) return (-1);
b5c45da1 117
118 return (0);
119}
120
799e58b9 121/* --- @km_samealgsp@ --- *
b5c45da1 122 *
799e58b9 123 * Arguments: @const kdata *kdx, *kdy@ = two key data objects
b5c45da1 124 *
799e58b9 125 * Returns: Nonzero if their two algorithm selections are the same.
b5c45da1 126 *
127 * Use: Checks sameness of algorithm selections: used to ensure that
128 * peers are using sensible algorithms.
129 */
130
799e58b9 131int km_samealgsp(const kdata *kdx, const kdata *kdy)
b5c45da1 132{
799e58b9
MW
133 const algswitch *a = &kdx->algs, *aa = &kdy->algs;
134
5b9f3d37
MW
135 return (kdx->grp->ops == kdy->grp->ops &&
136 kdx->grp->ops->samegrpp(kdx->grp, kdy->grp) &&
799e58b9 137 a->mgf == aa->mgf && a->h == aa->h &&
c70a7c5c
MW
138 a->bulk->ops == aa->bulk->ops &&
139 a->bulk->ops->samealgsp(a->bulk, aa->bulk));
b5c45da1 140}
141
799e58b9
MW
142/*----- Key data and key nodes --------------------------------------------*/
143
144typedef struct keyhalf {
145 const char *kind;
5b9f3d37
MW
146 int (*load)(key_file *, key *, key_data *,
147 const dhops *, kdata *, dstr *, dstr *);
799e58b9
MW
148 const char *kr;
149 key_file *kf;
150 fwatch w;
151 sym_table tab;
152} keyhalf;
153
154/* --- @kh_loadpub@, @kh_loadpriv@ --- *
155 *
5b9f3d37
MW
156 * Arguments: @const dhops *dh@ = Diffie--Hellman operations for key type
157 * @key_file *kf@ = key file from which the key was loaded
158 * @key *k@ = the key object we're loading
159 * @key_data *d@ = the key data to load
799e58b9
MW
160 * @kdata *kd@ = our key-data object to fill in
161 * @dstr *t@ = the key tag name
162 * @dstr *e@ = a string to write error tokens to
163 *
164 * Returns: Zero on success, @-1@ on error.
165 *
166 * Use: These functions handle the main difference between public and
5b9f3d37
MW
167 * private key halves. They are responsible for setting @grp@,
168 * @k@ and @K@ appropriately in all keys, handling the mismatch
169 * between the largely half-indifferent calling code and the
170 * group-specific loading functions.
799e58b9
MW
171 *
172 * The function @kh_loadpriv@ is also responsible for checking
173 * the group for goodness. We don't bother checking public
174 * keys, because each public key we actually end up using must
175 * share a group with a private key which we'll already have
176 * checked.
177 */
178
5b9f3d37
MW
179static int kh_loadpub(key_file *kf, key *k, key_data *d,
180 const dhops *dh, kdata *kd, dstr *t, dstr *e)
799e58b9
MW
181{
182 int rc;
183
5b9f3d37 184 if ((rc = dh->ldpub(kf, k, d, kd, t, e)) != 0)
799e58b9 185 goto fail_0;
5b9f3d37
MW
186 kd->grp->ops = dh;
187 if (kd->grp->ops->checkge(kd->grp, kd->K)) {
73174919 188 a_format(e, "bad-public-group-element", A_END);
799e58b9
MW
189 goto fail_1;
190 }
799e58b9
MW
191 return (0);
192
193fail_1:
5b9f3d37
MW
194 kd->grp->ops->freege(kd->grp, kd->K);
195 kd->grp->ops->freegrp(kd->grp);
799e58b9
MW
196fail_0:
197 return (-1);
198}
199
5b9f3d37
MW
200static int kh_loadpriv(key_file *kf, key *k, key_data *d,
201 const dhops *dh, kdata *kd, dstr *t, dstr *e)
799e58b9
MW
202{
203 int rc;
204 const char *err;
f1d5c891
MW
205 dhge *K;
206 int ok;
799e58b9 207
5b9f3d37 208 if ((rc = dh->ldpriv(kf, k, d, kd, t, e)) != 0)
799e58b9 209 goto fail_0;
5b9f3d37
MW
210 kd->grp->ops = dh;
211 if ((err = kd->grp->ops->checkgrp(kd->grp)) != 0) {
799e58b9
MW
212 a_format(e, "bad-group", "%s", err, A_END);
213 goto fail_1;
214 }
f1d5c891
MW
215 K = kd->grp->ops->mul(kd->grp, kd->k, 0);
216 ok = kd->grp->ops->eq(kd->grp, kd->K, K);
217 kd->grp->ops->freege(kd->grp, K);
218 if (!ok) {
219 a_format(e, "incorrect-public-key", A_END);
220 goto fail_1;
221 }
799e58b9
MW
222 return (0);
223
224fail_1:
5b9f3d37
MW
225 kd->grp->ops->freesc(kd->grp, kd->k);
226 kd->grp->ops->freege(kd->grp, kd->K);
227 kd->grp->ops->freegrp(kd->grp);
799e58b9
MW
228fail_0:
229 return (-1);
230}
231
232static struct keyhalf
233 priv = { "private", kh_loadpriv },
234 pub = { "public", kh_loadpub };
410c8acf 235
236/* --- @keymoan@ --- *
237 *
56814747 238 * Arguments: @const char *file@ = name of the file
e04c2d50
MW
239 * @int line@ = line number in file
240 * @const char *msg@ = error message
4d36660a 241 * @void *p@ = argument pointer (indicates which keyring)
410c8acf 242 *
e04c2d50 243 * Returns: ---
410c8acf 244 *
e04c2d50 245 * Use: Reports an error message about loading a key file.
410c8acf 246 */
247
248static void keymoan(const char *file, int line, const char *msg, void *p)
f43df819 249{
799e58b9 250 keyhalf *kh = p;
4d36660a
MW
251
252 if (!line) {
799e58b9 253 a_warn("KEYMGMT", "%s-keyring", kh->kind, "%s", file,
4d36660a
MW
254 "io-error", "?ERRNO", A_END);
255 } else {
799e58b9 256 a_warn("KEYMGMT", "%s-keyring", kh->kind, "%s", file, "line", "%d", line,
4d36660a
MW
257 "%s", msg, A_END);
258 }
f43df819 259}
410c8acf 260
799e58b9 261/* --- @kh_reopen@ --- *
fc5f4823 262 *
799e58b9 263 * Arguments: @keyhalf *kh@ = pointer to keyhalf structure
fc5f4823 264 *
799e58b9 265 * Returns: Zero on success, @-1@ on error.
fc5f4823 266 *
799e58b9
MW
267 * Use: Reopens the key file for the appropriate key half. If this
268 * fails, everything is left as it was; if it succeeds, then the
269 * old file is closed (if it was non-null) and the new one put
270 * in its place.
fc5f4823
MW
271 */
272
799e58b9 273static int kh_reopen(keyhalf *kh)
fc5f4823 274{
799e58b9 275 key_file *kf = CREATE(key_file);
fc5f4823 276
799e58b9
MW
277 if (key_open(kf, kh->kr, KOPEN_READ, keymoan, kh)) {
278 a_warn("KEYMGMT", "%s-keyring", kh->kind, "%s", kh->kr,
7f81b1b4 279 "io-error", "?ERRNO", A_END);
799e58b9
MW
280 DESTROY(kf);
281 return (-1);
799e58b9 282 }
cc807016
MW
283 if (kh->kf) {
284 key_close(kh->kf);
285 DESTROY(kh->kf);
286 }
287 kh->kf = kf;
288 return (0);
799e58b9 289}
fc5f4823 290
799e58b9
MW
291/* --- @kh_init@ --- *
292 *
293 * Arguments: @keyhalf *kh@ = pointer to keyhalf structure to set up
294 * @const char *kr@ = name of the keyring file
295 *
296 * Returns: ---
297 *
298 * Use: Initialize a keyhalf structure, maintaining the private or
299 * public keys. Intended to be called during initialization:
300 * exits if there's some kind of problem.
301 */
fc5f4823 302
799e58b9
MW
303static void kh_init(keyhalf *kh, const char *kr)
304{
305 kh->kr = kr;
306 fwatch_init(&kh->w, kr);
307 sym_create(&kh->tab);
308 kh->kf = 0;
309
310 if (kh_reopen(kh))
311 die(EXIT_FAILURE, "failed to load %s keyring `%s'", kh->kind, kr);
fc5f4823
MW
312}
313
799e58b9 314/* --- @kh_load@ --- *
410c8acf 315 *
799e58b9
MW
316 * Arguments: @keyhalf *kh@ = pointer to keyhalf
317 * @const char *tag@ = key tag to be loaded
318 * @int complainp@ = whether to complain about missing keys
410c8acf 319 *
799e58b9
MW
320 * Returns: Pointer to a @kdata@ structure if successful, or null on
321 * failure.
410c8acf 322 *
799e58b9
MW
323 * Use: Attempts to load a key from the current key file. This
324 * function always reads data from the file: it's used when
325 * there's a cache miss from @kh_find@, and when refreshing the
326 * known keys in @kh_refresh@. The returned kdata has a
327 * reference count of exactly 1, and has no home knode.
410c8acf 328 */
329
799e58b9 330static kdata *kh_load(keyhalf *kh, const char *tag, int complainp)
410c8acf 331{
52c03a2a 332 dstr t = DSTR_INIT;
4d36660a 333 dstr e = DSTR_INIT;
799e58b9
MW
334 key *k;
335 key_data **d;
336 kdata *kd;
337 const char *ty;
5b9f3d37
MW
338 const dhops *dh;
339 T( const dhgrp *g; )
52c03a2a 340
799e58b9 341 /* --- Find the key and grab its tag --- */
52c03a2a 342
799e58b9
MW
343 if (key_qtag(kh->kf, tag, &t, &k, &d)) {
344 if (complainp) {
345 a_warn("KEYMGMT", "%s-keyring", kh->kind, "%s", kh->kr,
346 "key-not-found", "%s", tag, A_END);
347 }
348 goto fail_0;
52c03a2a 349 }
350
799e58b9
MW
351 /* --- Find the key's group type and the appropriate operations --- *
352 *
353 * There are several places to look for the key type. The most obvious is
354 * the `kx-group' key attribute. But there's also the key type itself, for
355 * compatibility reasons.
356 */
52c03a2a 357
799e58b9
MW
358 ty = key_getattr(kh->kf, k, "kx-group");
359 if (!ty && strncmp(k->type, "tripe-", 6) == 0) ty = k->type + 6;
360 if (!ty) ty = "dh";
52c03a2a 361
5b9f3d37
MW
362 for (dh = dhtab; dh->name; dh++)
363 if (strcmp(dh->name, ty) == 0) goto founddh;
799e58b9
MW
364 a_warn("KEYMGMT", "%s-keyring", kh->kind,
365 "%s", kh->kr, "key", "%s", t.buf,
366 "unknown-group-type", "%s", ty, A_END);
367 goto fail_0;
368
5b9f3d37 369founddh:
799e58b9 370 kd = CREATE(kdata);
5b9f3d37 371 if (kh->load(kh->kf, k, *d, dh, kd, &t, &e)) {
799e58b9 372 a_warn("KEYMGMT", "%s-keyring", kh->kind,
01d12d8f 373 "%s", kh->kr, "key", "%s", t.buf,
4d36660a 374 "*%s", e.buf, A_END);
799e58b9 375 goto fail_1;
52c03a2a 376 }
377
799e58b9 378 if (algs_get(&kd->algs, &e, kh->kf, k) ||
e6a013d3 379 algs_check(&kd->algs, &e, kd->grp)) {
799e58b9
MW
380 a_warn("KEYMGMT", "%s-keyring", kh->kind,
381 "%s", kh->kr, "key", "%s", t.buf,
4d36660a 382 "*%s", e.buf, A_END);
799e58b9 383 goto fail_2;
410c8acf 384 }
52c03a2a 385
799e58b9 386 kd->tag = xstrdup(t.buf);
799e58b9
MW
387 kd->ref = 1;
388 kd->kn = 0;
fb6a9f13 389 kd->id = k->id;
799e58b9 390 kd->t_exp = k->exp;
52c03a2a 391
392 IF_TRACING(T_KEYMGMT, {
799e58b9 393 trace(T_KEYMGMT, "keymgmt: loaded %s key `%s'", kh->kind, t.buf);
52c03a2a 394 IF_TRACING(T_CRYPTO, {
5b9f3d37
MW
395 g = kd->grp;
396 g->ops->tracegrp(g);
397 if (kd->k)
398 trace(T_CRYPTO, "crypto: k = %s", g->ops->scstr(g, kd->k));
399 trace(T_CRYPTO, "crypto: K = %s", g->ops->gestr(g, kd->K));
c70a7c5c 400 kd->algs.bulk->ops->tracealgs(kd->algs.bulk);
52c03a2a 401 })
402 })
403
799e58b9 404 goto done;
52c03a2a 405
799e58b9 406fail_2:
5b9f3d37
MW
407 if (kd->k) kd->grp->ops->freesc(kd->grp, kd->k);
408 kd->grp->ops->freege(kd->grp, kd->K);
409 kd->grp->ops->freegrp(kd->grp);
799e58b9
MW
410fail_1:
411 DESTROY(kd);
412fail_0:
413 kd = 0;
414done:
52c03a2a 415 dstr_destroy(&t);
4d36660a 416 dstr_destroy(&e);
799e58b9 417 return (kd);
410c8acf 418}
419
799e58b9 420/* --- @kh_find@ --- *
410c8acf 421 *
799e58b9
MW
422 * Arguments: @keyhalf *kh@ = pointer to the keyhalf
423 * @const char *tag@ = key to be obtained
424 * @int complainp@ = whether to complain about missing keys
410c8acf 425 *
799e58b9 426 * Returns: A pointer to the kdata, or null on error.
410c8acf 427 *
799e58b9
MW
428 * Use: Obtains kdata, maybe from the cache. This won't update a
429 * stale cache entry, though @kh_refresh@ ought to have done
430 * that already. The returned kdata object may be shared with
431 * other users. (One of this function's responsibilities, over
432 * @kh_load@, is to set the home knode of a freshly loaded
433 * kdata.)
410c8acf 434 */
435
799e58b9 436static kdata *kh_find(keyhalf *kh, const char *tag, int complainp)
410c8acf 437{
799e58b9
MW
438 knode *kn;
439 kdata *kd;
440 unsigned f;
410c8acf 441
799e58b9
MW
442 kn = sym_find(&kh->tab, tag, -1, sizeof(knode), &f);
443
444 if (f) {
445 if (kn->f & KNF_BROKEN) {
446 T( if (complainp)
447 trace(T_KEYMGMT, "keymgmt: key `%s' marked as broken", tag); )
448 return (0);
449 }
450
451 kd = kn->kd;
452 if (kd) kd->ref++;
453 T( trace(T_KEYMGMT, "keymgmt: %scache hit for key `%s'",
454 kd ? "" : "negative ", tag); )
455 return (kd);
456 } else {
457 kd = kh_load(kh, tag, complainp);
458 kn->kd = kd;
459 kn->kh = kh;
460 kn->f = 0;
461 if (!kd)
462 kn->f |= KNF_BROKEN;
463 else {
464 kd->kn = kn;
465 kd->ref++;
466 }
467 return (kd);
410c8acf 468 }
410c8acf 469}
470
799e58b9 471/* --- @kh_refresh@ --- *
410c8acf 472 *
799e58b9 473 * Arguments: @keyhalf *kh@ = pointer to the keyhalf
410c8acf 474 *
799e58b9
MW
475 * Returns: Zero if nothing needs to be done; nonzero if peers should
476 * refresh their keys.
410c8acf 477 *
799e58b9
MW
478 * Use: Refreshes cached keys from files.
479 *
480 * Each active knode is examined to see if a new key is
481 * available: the return value is nonzero if any new keys are.
482 * A key is considered new if its algorithms, public key, or
483 * expiry time are/is different.
484 *
485 * Stub knodes (with no kdata attached) are removed, so that a
486 * later retry can succeed if the file has been fixed. (This
487 * doesn't count as a change, since no peers should be relying
488 * on a nonexistent key.)
410c8acf 489 */
490
799e58b9 491static int kh_refresh(keyhalf *kh)
410c8acf 492{
799e58b9
MW
493 knode *kn;
494 kdata *kd;
495 sym_iter i;
496 int changep = 0;
497
498 if (!fwatch_update(&kh->w, kh->kr) || kh_reopen(kh))
499 return (0);
500
501 T( trace(T_KEYMGMT, "keymgmt: rescan %s keyring `%s'", kh->kind, kh->kr); )
502 for (sym_mkiter(&i, &kh->tab); (kn = sym_next(&i)) != 0; ) {
503 if (!kn->kd) {
504 T( trace(T_KEYMGMT, "keymgmt: discard stub entry for key `%s'",
505 SYM_NAME(kn)); )
506 sym_remove(&kh->tab, kn);
507 continue;
508 }
509 if ((kd = kh_load(kh, SYM_NAME(kn), 1)) == 0) {
510 if (!(kn->f & KNF_BROKEN)) {
511 T( trace(T_KEYMGMT, "keymgmt: failed to load new key `%s': "
512 "marking it as broken",
513 SYM_NAME(kn)); )
514 kn->f |= KNF_BROKEN;
515 }
516 continue;
517 }
518 kn->f &= ~KNF_BROKEN;
519 if (kd->t_exp == kn->kd->t_exp &&
520 km_samealgsp(kd, kn->kd) &&
5b9f3d37 521 kd->grp->ops->eq(kd->grp, kd->K, kn->kd->K)) {
799e58b9
MW
522 T( trace(T_KEYMGMT, "keymgmt: key `%s' unchanged", SYM_NAME(kn)); )
523 continue;
524 }
525 T( trace(T_KEYMGMT, "keymgmt: loaded new version of key `%s'",
526 SYM_NAME(kn)); )
527 km_unref(kn->kd);
528 kd->kn = kn;
529 kn->kd = kd;
530 changep = 1;
531 }
410c8acf 532
799e58b9
MW
533 return (changep);
534}
410c8acf 535
799e58b9 536/*----- Main code ---------------------------------------------------------*/
410c8acf 537
799e58b9
MW
538const char *tag_priv;
539kdata *master;
410c8acf 540
410c8acf 541/* --- @km_init@ --- *
542 *
799e58b9
MW
543 * Arguments: @const char *privkr@ = private keyring file
544 * @const char *pubkr@ = public keyring file
545 * @const char *ptag@ = default private-key tag
410c8acf 546 *
547 * Returns: ---
548 *
799e58b9
MW
549 * Use: Initializes the key-management machinery, loading the
550 * keyrings and so on.
410c8acf 551 */
552
799e58b9 553void km_init(const char *privkr, const char *pubkr, const char *ptag)
410c8acf 554{
b5c45da1 555 const gchash *const *hh;
410c8acf 556
b5c45da1 557 for (hh = ghashtab; *hh; hh++) {
558 if ((*hh)->hashsz > MAXHASHSZ) {
559 die(EXIT_FAILURE, "INTERNAL ERROR: %s hash length %lu > MAXHASHSZ %d",
560 (*hh)->name, (unsigned long)(*hh)->hashsz, MAXHASHSZ);
561 }
562 }
563
799e58b9
MW
564 kh_init(&priv, privkr);
565 kh_init(&pub, pubkr);
566
567 tag_priv = ptag;
568 if ((master = km_findpriv(ptag)) == 0) exit(EXIT_FAILURE);
410c8acf 569}
570
799e58b9 571/* --- @km_reload@ --- *
410c8acf 572 *
799e58b9 573 * Arguments: ---
410c8acf 574 *
799e58b9 575 * Returns: Zero if OK, nonzero to force reloading of keys.
410c8acf 576 *
799e58b9 577 * Use: Checks the keyrings to see if they need reloading.
410c8acf 578 */
579
799e58b9 580int km_reload(void)
410c8acf 581{
799e58b9
MW
582 int changep = 0;
583 kdata *kd;
584
585 if (kh_refresh(&priv)) {
586 changep = 1;
587 kd = master->kn->kd;
35c8b547 588 if (kd != master) {
799e58b9
MW
589 km_unref(master);
590 km_ref(kd);
591 master = kd;
592 }
593 }
594 if (kh_refresh(&pub))
595 changep = 1;
596 return (changep);
597}
52c03a2a 598
799e58b9
MW
599/* --- @km_findpub@, @km_findpriv@ --- *
600 *
601 * Arguments: @const char *tag@ = key tag to load
602 *
603 * Returns: Pointer to the kdata object if successful, or null on error.
604 *
605 * Use: Fetches a public or private key from the keyring.
606 */
52c03a2a 607
799e58b9 608kdata *km_findpub(const char *tag) { return (kh_find(&pub, tag, 1)); }
410c8acf 609
799e58b9
MW
610kdata *km_findpriv(const char *tag)
611{
612 kdata *kd;
52c03a2a 613
799e58b9
MW
614 /* Unpleasantness for the sake of compatibility. */
615 if (!tag && (kd = kh_find(&priv, "tripe", 0)) != 0) return (kd);
616 else return (kh_find(&priv, tag ? tag : "tripe-dh", 1));
617}
52c03a2a 618
fb6a9f13
MW
619/* --- @km_findpubbyid@, @km_findprivbyid@ --- *
620 *
621 * Arguments: @uint32 id@ = key id to load
622 *
623 * Returns: Pointer to the kdata object if successful, or null on error.
624 *
625 * Use: Fetches a public or private key from the keyring given its
626 * numeric id.
627 */
628
629static kdata *findbyid(keyhalf *kh, uint32 id)
630{
631 key *k;
632 kdata *kd;
633
634 k = key_byid(kh->kf, id); if (!k) goto notfound;
635 kd = kh_find(kh, k->tag, 1); if (!kd) goto notfound;
636 if (kd->id != id) { km_unref(kd); goto notfound; }
637 return (kd);
638
639notfound:
640 a_warn("KX", "%s-keyring", kh->kind, "%s", kh->kr,
641 "unknown-key-id", "0x%08lx", (unsigned long)id,
642 A_END);
643 return (0);
644}
645
646kdata *km_findpubbyid(uint32 id) { return (findbyid(&pub, id)); }
647
648kdata *km_findprivbyid(uint32 id)
649{
650 if (id == master->id) { km_ref(master); return (master); }
651 else return findbyid(&priv, id);
652}
653
799e58b9
MW
654/* --- @km_tag@ --- *
655 *
656 * Arguments: @kdata *kd@ - pointer to the kdata object
657 *
658 * Returns: A pointer to the short tag by which the kdata was loaded.
659 */
52c03a2a 660
799e58b9 661const char *km_tag(kdata *kd) { return (SYM_NAME(kd->kn)); }
52c03a2a 662
799e58b9
MW
663/* --- @km_ref@ --- *
664 *
665 * Arguments: @kdata *kd@ = pointer to the kdata object
666 *
667 * Returns: ---
668 *
669 * Use: Claim a new reference to a kdata object.
670 */
52c03a2a 671
799e58b9 672void km_ref(kdata *kd) { kd->ref++; }
52c03a2a 673
799e58b9
MW
674/* --- @km_unref@ --- *
675 *
676 * Arguments: @kdata *kd@ = pointer to the kdata object
677 *
678 * Returns: ---
679 *
680 * Use: Releases a reference to a kdata object.
681 */
52c03a2a 682
799e58b9
MW
683void km_unref(kdata *kd)
684{
685 if (--kd->ref) return;
5b9f3d37
MW
686 if (kd->k) kd->grp->ops->freesc(kd->grp, kd->k);
687 kd->grp->ops->freege(kd->grp, kd->K);
688 kd->grp->ops->freegrp(kd->grp);
799e58b9 689 xfree(kd->tag);
5290b9d5 690 DESTROY(kd);
799e58b9
MW
691}
692
410c8acf 693/*----- That's all, folks -------------------------------------------------*/