server/admin.c: Remove spurious `ping' in usage message.
[tripe] / server / keymgmt.c
index 00c3295..33fa7e2 100644 (file)
@@ -145,7 +145,7 @@ typedef struct keyhalf {
   const char *kind;
   int (*load)(key_file *, key *, key_data *,
              const dhops *, kdata *, dstr *, dstr *);
-  const char *kr;
+  char *kr;
   key_file *kf;
   fwatch w;
   sym_table tab;
@@ -275,8 +275,6 @@ static int kh_reopen(keyhalf *kh)
   key_file *kf = CREATE(key_file);
 
   if (key_open(kf, kh->kr, KOPEN_READ, keymoan, kh)) {
-    a_warn("KEYMGMT", "%s-keyring", kh->kind, "%s", kh->kr,
-          "io-error", "?ERRNO", A_END);
     DESTROY(kf);
     return (-1);
   }
@@ -293,22 +291,21 @@ static int kh_reopen(keyhalf *kh)
  * Arguments:  @keyhalf *kh@ = pointer to keyhalf structure to set up
  *             @const char *kr@ = name of the keyring file
  *
- * Returns:    ---
+ * Returns:    Zero on success, @-1@ on error.
  *
  * Use:                Initialize a keyhalf structure, maintaining the private or
  *             public keys.  Intended to be called during initialization:
  *             exits if there's some kind of problem.
  */
 
-static void kh_init(keyhalf *kh, const char *kr)
+static int kh_init(keyhalf *kh, const char *kr)
 {
-  kh->kr = kr;
+  if (kh->kf) return (0);
+  kh->kr = xstrdup(kr);
+  if (kh_reopen(kh)) return (-1);
   fwatch_init(&kh->w, kr);
   sym_create(&kh->tab);
-  kh->kf = 0;
-
-  if (kh_reopen(kh))
-    die(EXIT_FAILURE, "failed to load %s keyring `%s'", kh->kind, kr);
+  return (0);
 }
 
 /* --- @kh_load@ --- *
@@ -397,6 +394,8 @@ founddh:
       if (kd->k)
        trace(T_CRYPTO, "crypto: k = %s", g->ops->scstr(g, kd->k));
       trace(T_CRYPTO, "crypto: K = %s", g->ops->gestr(g, kd->K));
+      trace(T_CRYPTO, "crypto: bulk transform = %s",
+           kd->algs.bulk->ops->name);
       kd->algs.bulk->ops->tracealgs(kd->algs.bulk);
     })
   })
@@ -533,10 +532,33 @@ static int kh_refresh(keyhalf *kh)
   return (changep);
 }
 
+/* --- @kh_clear@ --- *
+ *
+ * Arguments:  @keyhalf *kh@ = pointer to keyhalf structure
+ *
+ * Returns:    ---
+ *
+ * Use:                Clears out the keyhalf's keyring and flushes the cache.
+ */
+
+static void kh_clear(keyhalf *kh)
+{
+  sym_iter i;
+  knode *kn;
+
+  if (!kh->kf) return;
+  for (sym_mkiter(&i, &kh->tab); (kn = sym_next(&i)) != 0; )
+    if (kn->kd) km_unref(kn->kd);
+  sym_destroy(&kh->tab);
+  key_close(kh->kf);
+  xfree(kh->kr);
+  kh->kf = 0;
+}
+
 /*----- Main code ---------------------------------------------------------*/
 
-const char *tag_priv;
-kdata *master;
+char *tag_priv = 0;
+kdata *master = 0;
 
 /* --- @km_init@ --- *
  *
@@ -544,28 +566,37 @@ kdata *master;
  *             @const char *pubkr@ = public keyring file
  *             @const char *ptag@ = default private-key tag
  *
- * Returns:    ---
+ * Returns:    Zero on success, @-1@ on failure.
  *
  * Use:                Initializes the key-management machinery, loading the
  *             keyrings and so on.
  */
 
-void km_init(const char *privkr, const char *pubkr, const char *ptag)
+int km_init(const char *privkr, const char *pubkr, const char *ptag)
 {
   const gchash *const *hh;
+  kdata *kd;
 
   for (hh = ghashtab; *hh; hh++) {
     if ((*hh)->hashsz > MAXHASHSZ) {
-      die(EXIT_FAILURE, "INTERNAL ERROR: %s hash length %lu > MAXHASHSZ %d",
-         (*hh)->name, (unsigned long)(*hh)->hashsz, MAXHASHSZ);
+      a_warn("ABORT", "hash-size-too-large", "hash",
+            "%s", (*hh)->name, "size", "%lu", (*hh)->hashsz,
+            "limit", "%d", MAXHASHSZ, A_END);
+      abort();
     }
   }
 
-  kh_init(&priv, privkr);
-  kh_init(&pub, pubkr);
+  if (kh_init(&priv, privkr) || kh_init(&pub, pubkr))
+    return (-1);
 
-  tag_priv = ptag;
-  if ((master = km_findpriv(ptag)) == 0) exit(EXIT_FAILURE);
+  tag_priv = ptag ? xstrdup(ptag) : 0;
+  kh_refresh(&priv);
+
+  if ((kd = km_findpriv(tag_priv)) == 0) return (-1);
+  if (master) km_unref(master);
+  master = kd;
+
+  return (0);
 }
 
 /* --- @km_reload@ --- *
@@ -596,6 +627,26 @@ int km_reload(void)
   return (changep);
 }
 
+/* --- @km_clear@ --- *
+ *
+ * Arguments:  ---
+ *
+ * Returns:    ---
+ *
+ * Use:                Forget the currently loaded keyrings.  The @master@ key will
+ *             be cleared, but other keys already loaded will continue to
+ *             exist until their reference count drops to zero.  Call
+ *             @km_init@ to make everything work again.
+ */
+
+void km_clear(void)
+{
+  kh_clear(&priv);
+  kh_clear(&pub);
+  if (master) { km_unref(master); master = 0; }
+  if (tag_priv) { xfree(tag_priv); tag_priv = 0; }
+}
+
 /* --- @km_findpub@, @km_findpriv@ --- *
  *
  * Arguments:  @const char *tag@ = key tag to load