chiark / gitweb /
pubkey handling: Call sethash when needed
[secnet.git] / site.c
diff --git a/site.c b/site.c
index fda3dcc11c5bbc6d5d0de83ecfb8f7c9cf8b7463..e8b507ff0540fc2302420f0eccbb959897e22072 100644 (file)
--- a/site.c
+++ b/site.c
@@ -318,6 +318,7 @@ struct site {
     int ncomms;
     struct resolver_if *resolver;
     struct log_if *log;
+    struct hash_if *defhash;
     struct random_if *random;
     struct privcache_if *privkeys;
     struct sigprivkey_if *privkey_fixed;
@@ -902,7 +903,7 @@ static void peerkeys_maybe_incorporate(struct site *st, const char *file,
                                       int logcl_enoent)
 {
     struct peer_keyset *atsuffix=
-       keyset_load(file,&st->scratch,st->log,logcl_enoent);
+       keyset_load(file,&st->scratch,st->log,logcl_enoent,st->defhash);
     if (!atsuffix) return;
 
     if (st->peerkeys_current &&
@@ -946,6 +947,9 @@ static void peerkeys_check_for_update(struct site *st)
      *                  may be incomplete, unverified, or even malicious
      *                  only secnet may write or remove.
      *
+     *  <F>~tmp        update file from config manager, only mss may
+     *                  write or rename
+     *
      * secnet discards updates that are not more recent than (by
      * serial) the live file.  But it may not process updates
      * immediately.
@@ -960,6 +964,11 @@ static void peerkeys_check_for_update(struct site *st)
      *  write: rename something onto update
      *  read: read update,proc,live in that order and take max
      *
+     * We support only one concurrent secnet, one concurrent
+     * writing make-secnet-sites, and any number of readers.
+     * We want to maintain a live file at all times as that
+     * is what secnet actually reads at startup and uses.
+     *
      * Proof that this is sound:
      *   Let us regard update,proc,live as i=0,1,2
      *   Files contain public key sets and are manipulated as
@@ -989,14 +998,19 @@ static void peerkeys_check_for_update(struct site *st)
      *   (a) check live vs proc, proc>live, mv:
      *      j=2, i=1; S'(i)=-1, so S(i) is being reduced.  S'(j) is
      *      equal to S(i), and the rename is atomic [1], so S'(j) and
-     *      S'(i) are updated simultaneously.
-     *      S(j) is being increased.
+     *      S'(i) are updated simultaneously.  S(j) is being
+     *      increased.  (There are no hazards from concurrent writers;
+     *      only we ourselves (secnet) write to live or proc.)
      *   (b) check live vs proc, proc<=live, rm:
      *      j=2, i=1; S'(i)=-1, so S(i) is being reduced.  But
-     *      S(j) is >= $(i) throughout.
-     *   (c) mv update proc (when update does not exist):
+     *      S(j) is >= $(i) throughout.  (Again, no concurrent
+     *      writer hazards.)
+     *   (c) mv update proc (when proc does not exist):
      *      j=1, i=0; S(i) is being reduced to -1.  But simultaneously
-     *      S(j) is being increased to the old S(i).
+     *      S(j) is being increased to the old S(i).  Our precondition
+     *      (proc not existing) is not subject to a concurrent writer
+     *      hazards because only we write to proc; our action is
+     *      atomic and takes whatever update is available (if any).
      *
      * Proof of soundness for the mss reading operation:
      *   Let M be MAX(\forall S) at the point where mss reads update.
@@ -1054,7 +1068,7 @@ static void peerkeys_check_for_update(struct site *st)
 
     int r=rename(inputp,oursp);
     if (r) {
-       slog(st,LOG_ERROR,"failed to claim key update file %s as %s: %s\n",
+       slog(st,LOG_ERROR,"failed to claim key update file %s as %s: %s",
             inputp,oursp,strerror(errno));
        return;
     }
@@ -2410,14 +2424,15 @@ static void site_childpersist_clearkeys(void *sst, uint32_t newphase)
 }
 
 static void setup_sethash(struct site *st, dict_t *dict,
-                         struct hash_if **hash, struct cloc loc,
+                         struct cloc loc,
                          sig_sethash_fn *sethash, void *sigkey_st) {
-    if (!*hash) *hash=find_cl_if(dict,"hash",CL_HASH,True,"site",loc);
-    sethash(sigkey_st,*hash);
+    if (!st->defhash)
+       cfgfatal(loc,"site","other settings imply `hash' key is needed");
+    sethash(sigkey_st,st->defhash);
 }
 #define SETUP_SETHASH(k) do{                                           \
     if ((k)->sethash)                                                  \
-        setup_sethash(st,dict, &hash,loc, (k)->sethash,(k)->st);       \
+        setup_sethash(st,dict,loc, (k)->sethash,(k)->st);      \
 }while(0)
 
 static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context,
@@ -2515,7 +2530,7 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context,
     st->log=find_cl_if(dict,"log",CL_LOG,True,"site",loc);
     st->random=find_cl_if(dict,"random",CL_RANDOMSRC,True,"site",loc);
 
-    struct hash_if *hash=0;
+    st->defhash=find_cl_if(dict,"hash",CL_HASH,True,"site",loc);
 
     st->privkeys=find_cl_if(dict,"key-cache",CL_PRIVCACHE,False,"site",loc);
     if (!st->privkeys) {
@@ -2532,7 +2547,8 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context,
        pathprefix_template_init(&st->peerkeys_tmpl,st->peerkeys_path,
                                 PEERKEYS_SUFFIX_MAXLEN + 1 /* nul */);
        st->peerkeys_current=keyset_load(st->peerkeys_path,
-                                        &st->scratch,st->log,M_ERR);
+                                        &st->scratch,st->log,M_ERR,
+                                        st->defhash);
        if (fixed_pubkey) {
            fixed_pubkey->dispose(fixed_pubkey->st);
        }