chiark / gitweb /
make-secnet-sites: Fix error handling if caller is in wrong group
[secnet.git] / privcache.c
index 0c10197d8fc0fc2694e002ae2ce0a40330240c62..d790c30ad07402a1325c8340a3fdd169618bcaa7 100644 (file)
@@ -21,6 +21,7 @@
 #include "util.h"
 
 #define DEFAULT_SIZE 5
+#define DEFAULT_MAXPRIV_BYTES 4095
 
 struct ent {
     struct sigkeyid id;
@@ -34,79 +35,106 @@ struct privcache {
     struct pathprefix_template path;
     struct ent *ents;
     struct buffer_if databuf;
-    struct hash_if *defhash;
 };
 
+static bool_t uncached_load_file(
+                          const struct sigscheme_info *scheme,
+                          const char *path,
+                          struct buffer_if *databuf,
+                          struct sigprivkey_if **sigpriv_r,
+                          closure_t **closure_r,
+                          struct log_if *log);
+
 static struct sigprivkey_if *uncached_get(struct privcache *st,
                           const struct sigkeyid *id, struct log_if *log)
+{
+    sprintf(st->path.write_here, SIGKEYID_PR_FMT, SIGKEYID_PR_VAL(id));
+
+    const char *path=st->path.buffer;
+    const struct sigscheme_info *scheme;
+    for (scheme=sigschemes;
+        scheme->name;
+        scheme++)
+       if (scheme->algid == id->b[GRPIDSZ])
+           goto found;
+
+    slilog(log,M_ERR,"private key file %s not loaded (unknown algid)",
+          path);
+    return 0;
+
+ found:;
+    struct sigprivkey_if *sigpriv;
+    closure_t *cl;
+    bool_t ok=uncached_load_file(scheme,
+                             path,
+                             &st->databuf,
+                             &sigpriv,
+                             &cl,
+                             log);
+    return ok ? sigpriv : 0;
+}
+
+static bool_t uncached_load_file(
+                          const struct sigscheme_info *scheme,
+                          const char *path,
+                          struct buffer_if *databuf,
+                          struct sigprivkey_if **sigpriv_r,
+                          closure_t **closure_r,
+                          struct log_if *log)
 {
     bool_t ok=False;
     FILE *f=0;
+    struct sigprivkey_if *sigpriv=0;
 
-    sprintf(st->path.write_here, SIGKEYID_PR_FMT, SIGKEYID_PR_VAL(id));
-
-    f = fopen(st->path.buffer,"rb");
+    f=fopen(path,"rb");
     if (!f) {
        if (errno == ENOENT) {
            slilog(log,M_DEBUG,"private key %s not found",
-                  st->path.buffer);
+                  path);
        } else {
            slilog(log,M_ERR,"failed to open private key file %s",
-                  st->path.buffer);
+                  path);
        }
-       goto out;
+       goto error_out;
     }
 
     setbuf(f,0);
-    buffer_init(&st->databuf,0);
-    ssize_t got=fread(st->databuf.base,1,st->databuf.alloclen,f);
+    buffer_init(databuf,0);
+    ssize_t got=fread(databuf->base,1,databuf->alloclen,f);
     if (ferror(f)) {
        slilog(log,M_ERR,"failed to read private-key file %s",
-              st->path.buffer);
-       goto out;
+              path);
+       goto error_out;
     }
     if (!feof(f)) {
        slilog(log,M_ERR,"private key file %s longer than max %d",
-              st->path.buffer, (int)st->databuf.alloclen);
-       goto out;
+              path, (int)databuf->alloclen);
+       goto error_out;
     }
     fclose(f); f=0;
 
-    struct sigprivkey_if *sigpriv=0;
-    for (const struct sigscheme_info *scheme=sigschemes;
-        scheme->name;
-        scheme++) {
-       st->databuf.start=st->databuf.base;
-       st->databuf.size=got;
-       ok=scheme->loadpriv(scheme, &st->databuf, &sigpriv, log);
-       if (ok) {
-           if (sigpriv->sethash) {
-               if (!st->defhash) {
-                   slilog(log,M_ERR,
- "private key %s requires `hash' config key for privcache to load",
-                          st->path.buffer);
-                   sigpriv->dispose(sigpriv->st);
-                   sigpriv=0;
-                   goto out;
-               }
-               sigpriv->sethash(sigpriv->st,st->defhash);
-           }
-           goto out;
-       }
-    }
+    databuf->start=databuf->base;
+    databuf->size=got;
+    struct cloc loc = { .file=path, .line=0 };
+    ok=scheme->loadpriv(scheme, databuf, &sigpriv, closure_r, log, loc);
+    if (!ok) goto error_out; /* loadpriv will have logged */
 
-    slilog(log,M_ERR,"private key file %s not loaded (not recognised?)",
-          st->path.buffer);
+    *sigpriv_r=sigpriv;
 
   out:
     if (f) fclose(f);
-    return ok ? sigpriv : 0;
+    return ok;
+
+ error_out:
+    if (sigpriv) sigpriv->dispose(sigpriv->st);
+    ok=False;
+    goto out;
 }
 
 static struct sigprivkey_if *privcache_lookup(void *sst,
                                              const struct sigkeyid *id,
                                              struct log_if *log) {
-    struct privcache *st = sst;
+    struct privcache *st=sst;
     int was;
     struct ent result;
 
@@ -118,10 +146,10 @@ static struct sigprivkey_if *privcache_lookup(void *sst,
     }
 
     if (st->used < st->alloc) {
-       was = st->used;
+       was=st->used;
        st->used++;
     } else {
-       was = st->used-1;
+       was=st->used-1;
        if (st->ents[was].sigpriv) {
            st->ents[was].sigpriv->dispose(st->ents[was].sigpriv->st);
        }
@@ -132,7 +160,7 @@ static struct sigprivkey_if *privcache_lookup(void *sst,
 
  found:
     memmove(&st->ents[1], &st->ents[0], sizeof(st->ents[0]) * was);
-    st->ents[0] = result;
+    st->ents[0]=result;
     return result.sigpriv;
 }
 
@@ -153,7 +181,6 @@ static list_t *privcache_apply(closure_t *self, struct cloc loc,
     st->ents=0;
     st->path.buffer=0;
     st->used=st->alloc=0;
-    st->defhash=0;
 
     item=list_elem(args,0);
     if (!item || item->type!=t_dict)
@@ -167,18 +194,45 @@ static list_t *privcache_apply(closure_t *self, struct cloc loc,
     st->used=0;
 
     int32_t buflen=dict_read_number(dict,"privkey-max",False,"privcache",loc,
-                                   4095);
+                                   DEFAULT_MAXPRIV_BYTES);
     buffer_new(&st->databuf,buflen+1);
 
     const char *path=dict_read_string(dict,"privkeys",True,"privcache",loc);
     pathprefix_template_init(&st->path,path,KEYIDSZ*2);
 
-    st->defhash=find_cl_if(dict,"hash",CL_HASH,False,"site",loc);
-
     return new_closure(&st->cl);
 }
 
+static list_t *loadprivate_apply(closure_t *self, struct cloc loc,
+                              dict_t *context, list_t *args)
+{
+    CL_GET_STR_ARG(0,algname,"algorithm name");
+    CL_GET_STR_ARG(1,path,"private key path");
+
+    const struct sigscheme_info *sch=sigscheme_lookup(algname);
+    if (!sch) cfgfatal(algname_i->loc,"load-private",
+                      "unknown algorithm `%s'",algname);
+
+    struct buffer_if databuf;
+    buffer_new(&databuf,DEFAULT_MAXPRIV_BYTES);
+    BUF_ALLOC(&databuf,"load-private data buf");
+
+    struct cfgfile_log log;
+    cfgfile_log_init(&log,loc,"load-private");
+
+    struct sigprivkey_if *sigpriv;
+    closure_t *cl;
+    bool_t ok=
+       uncached_load_file(sch,path,&databuf,&sigpriv,&cl,&log.log);
+    if (!ok) cfgfatal(loc,"load-private","private key loading failed");
+
+    BUF_FREE(&databuf);
+    buffer_destroy(&databuf);
+    return new_closure(cl);
+}
+
 void privcache_module(dict_t *dict)
 {
     add_closure(dict,"priv-cache",privcache_apply);
+    add_closure(dict,"load-private",loadprivate_apply);
 }