Add notion of `ephemeral' associations and a goodbye protocol.
[tripe] / server / admin.c
index fcf27d3..54883af 100644 (file)
@@ -9,19 +9,18 @@
  *
  * This file is part of Trivial IP Encryption (TrIPE).
  *
- * TrIPE is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * TrIPE is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your
+ * option) any later version.
  *
- * TrIPE is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * TrIPE is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with TrIPE; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with TrIPE.  If not, see <https://www.gnu.org/licenses/>.
  */
 
 /*----- Header files ------------------------------------------------------*/
@@ -285,14 +284,11 @@ void a_vformat(dstr *d, const char *fmt, va_list *ap)
       } else if (strcmp(fmt, "?B64") == 0) {
        const octet *p = va_arg(*ap, const octet *);
        size_t n = va_arg(*ap, size_t);
-       base64_ctx b64;
+       codec *b64 = base64_class.encoder(CDCF_NOEQPAD, "", 0);
        dstr_putc(d, ' ');
-       base64_init(&b64);
-       b64.indent = "";
-       b64.maxline = 0;
-       base64_encode(&b64, p, n, d);
-       base64_encode(&b64, 0, 0, d);
-       while (d->len && d->buf[d->len - 1] == '=') d->len--;
+       b64->ops->code(b64, p, n, d);
+       b64->ops->code(b64, 0, 0, d);
+       b64->ops->destroy(b64);
       } else if (strcmp(fmt, "?TOKENS") == 0) {
        const char *const *av = va_arg(*ap, const char *const *);
        while (*av) u_quotify(d, *av++);
@@ -555,7 +551,7 @@ void a_quit(void)
 {
   close(sock.fd);
   unlink(sockname);
-  FOREACH_PEER(p, { p_destroy(p); });
+  FOREACH_PEER(p, { p_destroy(p, 1); });
   ps_quit();
   exit(0);
 }
@@ -1114,7 +1110,6 @@ static void a_resolve(admin *a, admin_resop *r, const char *tag,
     goto fail;
   }
   r->sa.sin.sin_family = AF_INET;
-  r->sasz = sizeof(r->sa.sin);
   r->addr = xstrdup(av[i]);
   if (!av[i + 1])
     pt = TRIPE_PORT;
@@ -1227,7 +1222,6 @@ static void a_doadd(admin_resop *r, int rc)
   T( trace(T_ADMIN, "admin: done add op %s", BGTAG(add)); )
 
   if (rc == ARES_OK) {
-    add->peer.sasz = add->r.sasz;
     add->peer.sa = add->r.sa;
     if (p_findbyaddr(&add->r.sa))
       a_bgfail(&add->r.bg, "peer-addr-exists", "?ADDR", &add->r.sa, A_END);
@@ -1240,6 +1234,8 @@ static void a_doadd(admin_resop *r, int rc)
   }
 
   if (add->peer.tag) xfree(add->peer.tag);
+  if (add->peer.privtag) xfree(add->peer.privtag);
+  if (add->peer.knock) xfree(add->peer.knock);
   xfree(add->peer.name);
 }
 
@@ -1265,6 +1261,7 @@ static void acmd_add(admin *a, unsigned ac, char *av[])
   add->peer.name = 0;
   add->peer.tag = 0;
   add->peer.privtag = 0;
+  add->peer.knock = 0;
   add->peer.t_ka = 0;
   add->peer.tops = tun_default;
   add->peer.f = 0;
@@ -1288,17 +1285,21 @@ static void acmd_add(admin *a, unsigned ac, char *av[])
     })
     OPTTIME("-keepalive", t, { add->peer.t_ka = t; })
     OPT("-cork", { add->peer.f |= KXF_CORK; })
+    OPT("-ephemeral", { add->peer.f |= PSF_EPHEM; })
     OPTARG("-key", arg, {
-      if (add->peer.tag)
-       xfree(add->peer.tag);
+      if (add->peer.tag) xfree(add->peer.tag);
       add->peer.tag = xstrdup(arg);
     })
-    OPT("-mobile", { add->peer.f |= PSF_MOBILE; })
+    OPT("-mobile", { add->peer.f |= PSF_MOBILE | PSF_EPHEM; })
     OPTARG("-priv", arg, {
-      if (add->peer.privtag)
-       xfree(add->peer.privtag);
+      if (add->peer.privtag) xfree(add->peer.privtag);
       add->peer.privtag = xstrdup(arg);
     })
+    OPTARG("-knock", arg, {
+      if (add->peer.knock) xfree(add->peer.knock);
+      add->peer.knock = xstrdup(arg);
+      add->peer.f |= PSF_EPHEM;
+    })
   });
 
   /* --- Make sure someone's not got there already --- */
@@ -1325,6 +1326,7 @@ fail:
   if (add->peer.name) xfree(add->peer.name);
   if (add->peer.tag) xfree(add->peer.tag);
   if (add->peer.privtag) xfree(add->peer.privtag);
+  if (add->peer.knock) xfree(add->peer.knock);
   xfree(add);
   return;
 }
@@ -1720,7 +1722,7 @@ static void acmd_algs(admin *a, unsigned ac, char *av[])
 {
   peer *p;
   const kdata *kd;
-  const group *g;
+  const dhgrp *g;
   const algswitch *algs;
 
   if (!ac)
@@ -1729,47 +1731,25 @@ static void acmd_algs(admin *a, unsigned ac, char *av[])
     if ((p = a_findpeer(a, av[0])) == 0) return;
     kd = p->kx.kpriv;
   }
-  g = kd->g;
+  g = kd->grp;
   algs = &kd->algs;
 
-  a_info(a,
-        "kx-group=%s", g->ops->name,
-        "kx-group-order-bits=%lu", (unsigned long)mp_bits(g->r),
-        "kx-group-elt-bits=%lu", (unsigned long)g->nbits,
-        A_END);
+  g->ops->grpinfo(g, a);
   a_info(a,
         "hash=%s", algs->h->name,
         "mgf=%s", algs->mgf->name,
         "hash-sz=%lu", (unsigned long)algs->h->hashsz,
         A_END);
   a_info(a,
-        "bulk-transform=%s", algs->bulk->name,
-        "bulk-overhead=%lu", (unsigned long)algs->bulk->overhead(algs),
+        "bulk-transform=%s", algs->bulk->ops->name,
+        "bulk-overhead=%lu",
+        (unsigned long)algs->bulk->ops->overhead(algs->bulk),
         A_END);
-  if (algs->c) {
-    a_info(a,
-          "cipher=%s", algs->c->name,
-          "cipher-keysz=%lu", (unsigned long)algs->cksz,
-          "cipher-blksz=%lu", (unsigned long)algs->c->blksz,
-          A_END);
-  }
+  algs->bulk->ops->alginfo(algs->bulk, a);
   a_info(a,
-        "cipher-data-limit=%lu", (unsigned long)algs->expsz,
+        "cipher-data-limit=%lu",
+        (unsigned long)algs->bulk->ops->expsz(algs->bulk),
         A_END);
-  if (algs->m) {
-    a_info(a,
-          "mac=%s", algs->m->name,
-          "mac-keysz=%lu", (unsigned long)algs->mksz,
-          "mac-tagsz=%lu", (unsigned long)algs->tagsz,
-          A_END);
-  }
-  if (algs->b) {
-    a_info(a,
-          "blkc=%.*s", strlen(algs->b->name) - 4, algs->b->name,
-          "blkc-keysz=%lu", (unsigned long)algs->bksz,
-          "blkc-blksz=%lu", (unsigned long)algs->b->blksz,
-          A_END);
-  }
   a_ok(a);
 }
 
@@ -1805,42 +1785,50 @@ static void acmd_getchal(admin *a, unsigned ac, char *av[])
   buf b;
 
   buf_init(&b, buf_i, PKBUFSZ);
-  c_new(&b);
+  c_new(0, 0, &b);
   a_info(a, "?B64", BBASE(&b), (size_t)BLEN(&b), A_END);
   a_ok(a);
 }
 
 static void acmd_checkchal(admin *a, unsigned ac, char *av[])
 {
-  base64_ctx b64;
+  codec *b64 = base64_class.decoder(CDCF_NOEQPAD);
+  int err;
   buf b;
   dstr d = DSTR_INIT;
 
-  base64_init(&b64);
-  base64_decode(&b64, av[0], strlen(av[0]), &d);
-  base64_decode(&b64, 0, 0, &d);
-  buf_init(&b, d.buf, d.len);
-  if (c_check(&b) || BBAD(&b) || BLEFT(&b))
-    a_fail(a, "invalid-challenge", A_END);
-  else
-    a_ok(a);
+  if ((err = b64->ops->code(b64, av[0], strlen(av[0]), &d)) != 0 ||
+      (err = b64->ops->code(b64, 0, 0, &d)) != 0)
+    a_fail(a, "bad-base64", "%s", codec_strerror(err), A_END);
+  else {
+    buf_init(&b, d.buf, d.len);
+    if (c_check(0, 0, &b) || BBAD(&b) || BLEFT(&b))
+      a_fail(a, "invalid-challenge", A_END);
+    else
+      a_ok(a);
+  }
+  b64->ops->destroy(b64);
   dstr_destroy(&d);
 }
 
 static void acmd_greet(admin *a, unsigned ac, char *av[])
 {
   peer *p;
-  base64_ctx b64;
+  int err;
+  codec *b64;
   dstr d = DSTR_INIT;
 
-  if ((p = a_findpeer(a, av[0])) != 0) {
-    base64_init(&b64);
-    base64_decode(&b64, av[1], strlen(av[1]), &d);
-    base64_decode(&b64, 0, 0, &d);
+  if ((p = a_findpeer(a, av[0])) == 0) return;
+  b64 = base64_class.decoder(CDCF_NOEQPAD);
+  if ((err = b64->ops->code(b64, av[1], strlen(av[1]), &d)) != 0 ||
+      (err = b64->ops->code(b64, 0, 0, &d)) != 0)
+    a_fail(a, "bad-base64", "%s", codec_strerror(err), A_END);
+  else {
     p_greet(p, d.buf, d.len);
-    dstr_destroy(&d);
     a_ok(a);
   }
+  b64->ops->destroy(b64);
+  dstr_destroy(&d);
 }
 
 static void acmd_addr(admin *a, unsigned ac, char *av[])
@@ -1865,12 +1853,17 @@ static void acmd_peerinfo(admin *a, unsigned ac, char *av[])
   if ((p = a_findpeer(a, av[0])) != 0) {
     ps = p_spec(p);
     a_info(a, "tunnel=%s", ps->tops->name, A_END);
+    if (ps->knock) a_info(a, "knock=%s", ps->knock, A_END);
     a_info(a, "key=%s", p_tag(p),
           "current-key=%s", p->kx.kpub->tag, A_END);
     if ((ptag = p_privtag(p)) == 0) ptag = "(default)";
     a_info(a, "private-key=%s", ptag,
           "current-private-key=%s", p->kx.kpriv->tag, A_END);
     a_info(a, "keepalive=%lu", ps->t_ka, A_END);
+    a_info(a, "corked=%s", BOOL(p->kx.f&KXF_CORK),
+          "mobile=%s", BOOL(ps->f&PSF_MOBILE),
+          "ephemeral=%s", BOOL(ps->f&PSF_EPHEM),
+          A_END);
     a_ok(a);
   }
 }
@@ -1925,7 +1918,7 @@ static void acmd_kill(admin *a, unsigned ac, char *av[])
   peer *p;
 
   if ((p = a_findpeer(a, av[0])) != 0) {
-    p_destroy(p);
+    p_destroy(p, 1);
     a_ok(a);
   }
 }
@@ -2000,6 +1993,7 @@ static const acmd acmdtab[] = {
   { "reload",  0,                      0,      0,      acmd_reload },
   { "servinfo",        0,                      0,      0,      acmd_servinfo },
   { "setifname", "PEER NEW-NAME",      2,      2,      acmd_setifname },
+  { "stats",   "PEER",                 1,      1,      acmd_stats },
   { "svcclaim",        "SERVICE VERSION",      2,      2,      acmd_svcclaim },
   { "svcensure", "SERVICE [VERSION]",  1,      2,      acmd_svcensure },
   { "svcfail", "JOBID TOKENS...",      1,      0xffff, acmd_svcfail },
@@ -2010,7 +2004,6 @@ static const acmd acmdtab[] = {
   { "svcrelease", "SERVICE",           1,      1,      acmd_svcrelease },
   { "svcsubmit", "[OPTIONS] SERVICE TOKENS...",
                                        2,      0xffff, acmd_svcsubmit },
-  { "stats",   "PEER",                 1,      1,      acmd_stats },
 #ifndef NTRACE
   { "trace",   "[OPTIONS]",            0,      1,      acmd_trace },
 #endif
@@ -2379,7 +2372,6 @@ again:
 
   sig_add(&s_term, SIGTERM, a_sigdie, 0);
   sig_add(&s_hup, SIGHUP, a_sighup, 0);
-  signal(SIGPIPE, SIG_IGN);
   sigaction(SIGINT, 0, &sa);
   if (sa.sa_handler != SIG_IGN)
     sig_add(&s_int, SIGINT, a_sigdie, 0);