Rearrange the file tree.
[u/mdw/catacomb] / cookie.c
diff --git a/cookie.c b/cookie.c
deleted file mode 100644 (file)
index 8fa07da..0000000
--- a/cookie.c
+++ /dev/null
@@ -1,694 +0,0 @@
-/* -*-c-*-
- *
- * $Id$
- *
- * Generate and validate cryptographic cookies
- *
- * (c) 1999 Mark Wooding
- */
-
-/*----- Licensing notice --------------------------------------------------*
- *
- * This file is part of Catacomb.
- *
- * Catacomb 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.
- *
- * Catacomb 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 Catacomb; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/*----- Header files ------------------------------------------------------*/
-
-#define _FILE_OFFSET_BITS 64
-
-#include "config.h"
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#include <mLib/base64.h>
-#include <mLib/bits.h>
-#include <mLib/dstr.h>
-#include <mLib/mdwopt.h>
-#include <mLib/quis.h>
-#include <mLib/report.h>
-#include <mLib/sub.h>
-
-#include "cc.h"
-#include "key.h"
-#include "gmac.h"
-#include "getdate.h"
-
-/*----- Handy global state ------------------------------------------------*/
-
-static const char *keyfile = "keyring";
-
-/*----- Cookie format -----------------------------------------------------*/
-
-/* --- Cookie header structure (unpacked) --- */
-
-typedef struct cookie {
-  uint32 k;
-  time_t exp;
-} cookie;
-
-/* --- Size of a cookie header (packed) --- */
-
-#define COOKIE_SZ (4 + 8)
-
-/* --- @COOKIE_PACK@ --- *
- *
- * Arguments:  @p@ = pointer to destination buffer
- *             @c@ = pointer to source cookie header block
- *
- * Use:                Packs a cookie header into an octet buffer in a machine-
- *             independent way.
- */
-
-#define COOKIE_PACK(p, c) do {                                         \
-  octet *_p = (octet *)(p);                                            \
-  const cookie *_c = (c);                                              \
-  STORE32(_p + 0, _c->k);                                              \
-  STORE32(_p + 4, ((_c->exp & ~MASK32) >> 16) >> 16);                  \
-  STORE32(_p + 8, _c->exp);                                            \
-} while (0)
-
-/* --- @COOKIE_UNPACK@ --- *
- *
- * Arguments:  @c@ = pointer to destination cookie header
- *             @p@ = pointer to source buffer
- *
- * Use:                Unpacks a cookie header from an octet buffer into a
- *             machine-specific but comprehensible structure.
- */
-
-#define COOKIE_UNPACK(c, p) do {                                       \
-  cookie *_c = (c);                                                    \
-  const octet *_p = (const octet *)(p);                                        \
-  _c->k = LOAD32(_p + 0);                                              \
-  _c->exp = ((time_t)(((LOAD32(_p + 4) << 16) << 16) & ~MASK32) |      \
-            (time_t)LOAD32(_p + 8));                                   \
-} while (0)
-
-/*----- Useful shared functions -------------------------------------------*/
-
-/* --- @doopen@ --- *
- *
- * Arguments:  @key_file *f@ = pointer to key file block
- *             @unsigned how@ = method to open file with
- *
- * Returns:    ---
- *
- * Use:                Opens a key file and handles errors by panicking
- *             appropriately.
- */
-
-static void doopen(key_file *f, unsigned how)
-{
-  if (key_open(f, keyfile, how, key_moan, 0)) {
-    die(EXIT_FAILURE, "couldn't open file `%s': %s",
-       keyfile, strerror(errno));
-  }
-}
-
-/* --- @doclose@ --- *
- *
- * Arguments:  @key_file *f@ = pointer to key file block
- *
- * Returns:    ---
- *
- * Use:                Closes a key file and handles errors by panicking
- *             appropriately.
- */
-
-static void doclose(key_file *f)
-{
-  switch (key_close(f)) {
-    case KWRITE_FAIL:
-      die(EXIT_FAILURE, "couldn't write file `%s': %s",
-         keyfile, strerror(errno));
-    case KWRITE_BROKEN:
-      die(EXIT_FAILURE, "keyring file `%s' broken: %s (repair manually)",
-         keyfile, strerror(errno));
-  }
-}
-
-/* --- @getmac@ --- *
- *
- * Arguments:  @key *k@ = key to use
- *             @const char *app@ = application name
- *
- * Returns:    The MAC to use.
- *
- * Use:                Finds the right MAC for the given key.
- */
-
-static gmac *getmac(key *k, const char *app)
-{
-  dstr t = DSTR_INIT;
-  dstr d = DSTR_INIT;
-  char *p = 0;
-  const char *q;
-  size_t n;
-  key_bin kb;
-  key_packdef kp;
-  const gcmac *cm;
-  int e;
-  gmac *m;
-
-  /* --- Set up --- */
-
-  key_fulltag(k, &t);
-
-  /* --- Pick out the right MAC --- */
-
-  n = strlen(app);
-  if ((q = key_getattr(0, k, "mac")) != 0) {
-    dstr_puts(&d, q);
-    p = d.buf;
-  } else if (strncmp(k->type, app, n) == 0 && k->type[n] == '-') {
-    dstr_puts(&d, k->type);
-    p = d.buf + n + 1;
-  } else
-    die(EXIT_FAILURE, "no MAC algorithm for key `%s'", t.buf);
-  if ((cm = gmac_byname(p)) == 0) {
-    die(EXIT_FAILURE, "MAC algorithm `%s' not found in key `%s'",
-       p, t.buf);
-  }
-
-  /* --- Unlock the key --- */
-
-  kp.e = KENC_BINARY;
-  kp.p = &kb;
-  if ((e = key_unpack(&kp, k->k, &t)) != 0) {
-    die(EXIT_FAILURE, "error unpacking key `%s': %s",
-       t.buf, key_strerror(e));
-  }
-
-  /* --- Make the MAC object --- */
-
-  if (keysz(kb.sz, cm->keysz) != kb.sz)
-    die(EXIT_FAILURE, "key %s has bad length (%lu) for MAC %s",
-       t.buf, (unsigned long)kb.sz, cm->name);
-  m = cm->key(kb.k, kb.sz);
-  key_unpackdone(&kp);
-  return (m);
-}
-
-/*----- Command implementation --------------------------------------------*/
-
-/* --- @cmd_gen@ --- */
-
-static int cmd_gen(int argc, char *argv[])
-{
-  key_file f;
-  key *k;
-  gmac *m;
-  ghash *h;
-  const char *tag = "cookie";
-  int err;
-  cookie c = { 0, KEXP_EXPIRE };
-  unsigned fl = 0;
-  int bits = 32;
-  const octet *t;
-  dstr d = DSTR_INIT;
-  octet buf[COOKIE_SZ];
-  base64_ctx b;
-
-  /* --- Various useful flag bits --- */
-
-#define f_bogus 1u
-
-  /* --- Parse options for the subcommand --- */
-
-  for (;;) {
-    static struct option opt[] = {
-      { "bits",                OPTF_ARGREQ,    0,      'b' },
-      { "expire",      OPTF_ARGREQ,    0,      'e' },
-      { "key",         OPTF_ARGREQ,    0,      'k' },
-      { 0,             0,              0,      0 }
-    };
-    int i = mdwopt(argc, argv, "+b:e:i:t:", opt, 0, 0, 0);
-    if (i < 0)
-      break;
-
-    /* --- Handle the various options --- */
-
-    switch (i) {
-
-      /* --- Fetch a size in bits --- */
-
-      case 'b':
-       if (!(bits = atoi(optarg)) || bits % 8)
-         die(EXIT_FAILURE, "bad number of bits: `%s'", optarg);
-       break;
-
-      /* --- Fetch an expiry time --- */
-
-      case 'e':
-       if (strcmp(optarg, "forever") == 0)
-         c.exp = KEXP_FOREVER;
-       else if ((c.exp = get_date(optarg, 0)) == -1)
-         die(EXIT_FAILURE, "bad expiry date: `%s'", optarg);
-       break;
-
-      /* --- Fetch a key type --- */
-
-      case 'k':
-       tag = optarg;
-       break;
-
-      /* --- Other things are bogus --- */
-
-      default:
-       fl |= f_bogus;
-       break;
-    }
-  }
-
-  /* --- Various sorts of bogosity --- */
-
-  if (fl & f_bogus || optind + 1 < argc)
-    die(EXIT_FAILURE,
-       "Usage: generate [-b BITS] [-e TIME] [-k TAG] [DATA]");
-
-  /* --- Choose a default expiry time --- */
-
-  if (c.exp == KEXP_EXPIRE)
-    c.exp = time(0) + 7 * 24 * 60 * 60;
-
-  /* --- Open the key file and get the key --- */
-
-  doopen(&f, KOPEN_WRITE);
-  if ((k = key_bytag(&f, tag)) == 0) {
-    die(EXIT_FAILURE, "no key with tag `%s' in keyring `%s'",
-       tag, keyfile);
-  }
-
-  c.k = k->id;
-  if ((err = key_used(&f, k, c.exp)) != 0)
-    die(EXIT_FAILURE, "can't generate cookie: %s", key_strerror(err));
-  m = getmac(k, "cookie");
-  if (bits/8 > GM_CLASS(m)->hashsz) {
-    die(EXIT_FAILURE, "inapproriate bit length for `%s' MACs",
-       GM_CLASS(m)->name);
-  }
-
-  /* --- Store and MAC the cookie --- */
-
-  COOKIE_PACK(buf, &c);
-
-  h = GM_INIT(m);
-  GH_HASH(h, buf, sizeof(buf));
-  if (argv[optind])
-    GH_HASH(h, argv[optind], strlen(argv[optind]));
-  t = GH_DONE(h, 0);
-
-  /* --- Encode and emit the finished cookie --- */
-
-  base64_init(&b);
-  b.indent = "";
-  base64_encode(&b, buf, sizeof(buf), &d);
-  base64_encode(&b, t, bits/8, &d);
-  base64_encode(&b, 0, 0, &d);
-  DWRITE(&d, stdout);
-  fputc('\n', stdout);
-  DDESTROY(&d);
-  GH_DESTROY(h);
-  GM_DESTROY(m);
-
-  doclose(&f);
-  return (0);
-
-#undef f_bogus
-}
-
-/* --- @cmd_verify@ --- */
-
-static int cmd_verify(int argc, char *argv[])
-{
-  key_file f;
-  dstr d = DSTR_INIT;
-  unsigned fl = 0;
-  int bits = -1, minbits = 32;
-  int v = 1;
-  base64_ctx b;
-  gmac *m;
-  ghash *h;
-  cookie c;
-  key *k;
-  int cbits;
-  const octet *t;
-  time_t now = time(0);
-
-  /* --- Various useful flag bits --- */
-
-#define f_bogus 1u
-#define f_forever 2u
-#define f_utc 4u
-
-  /* --- Parse options for the subcommand --- */
-
-  for (;;) {
-    static struct option opt[] = {
-      { "bits",                OPTF_ARGREQ,    0,      'b' },
-      { "min-bits",    OPTF_ARGREQ,    0,      'm' },
-      { "forever",     0,              0,      'f' },
-      { "quiet",       0,              0,      'q' },
-      { "verbose",     0,              0,      'v' },
-      { "utc",         0,              0,      'u' },
-      { 0,             0,              0,      0 }
-    };
-    int i = mdwopt(argc, argv, "+b:m:fqvu", opt, 0, 0, 0);
-    if (i < 0)
-      break;
-
-    /* --- Handle the various options --- */
-
-    switch (i) {
-
-      /* --- Fetch a size in bits --- */
-
-      case 'b':
-       if (!(bits = atoi(optarg)) || bits % 8)
-         die(EXIT_FAILURE, "bad number of bits: `%s'", optarg);
-       break;
-      case 'm':
-       if (!(minbits = atoi(optarg)) || minbits % 8)
-         die(EXIT_FAILURE, "bad number of bits: `%s'", optarg);
-       break;
-
-      /* --- Miscellaneous flags --- */
-
-      case 'f':
-       fl |= f_forever;
-       break;
-      case 'u':
-       fl |= f_utc;
-       break;
-      case 'q':
-       if (v > 0) v--;
-       break;
-      case 'v':
-       v++;
-       break;
-
-      /* --- Other things are bogus --- */
-
-      default:
-       fl |= f_bogus;
-       break;
-    }
-  }
-
-  /* --- Various sorts of bogosity --- */
-
-  if (fl & f_bogus || optind == argc || optind + 2 < argc) {
-    die(EXIT_FAILURE,
-       "Usage: verify [-fuqv] [-b BITS] [-m BITS] COOKIE [DATA]");
-  }
-  doopen(&f, KOPEN_READ);
-
-  /* --- Decode the base64 wrapping --- */
-
-  base64_init(&b);
-  base64_decode(&b, argv[optind], strlen(argv[optind]), &d);
-  base64_decode(&b, 0, 0, &d);
-
-  if (d.len < COOKIE_SZ + 1) {
-    if (v) printf("FAIL cookie too small\n");
-    goto fail;
-  }
-
-  /* --- Extract the relevant details --- */
-
-  COOKIE_UNPACK(&c, d.buf);
-
-  if (v > 1) {
-    char buf[64];
-    if (c.exp == KEXP_FOREVER)
-      strcpy(buf, "forever");
-    else {
-      struct tm *tm;
-      const char *fmt;
-
-      if (fl & f_utc) {
-       tm = gmtime(&c.exp);
-       fmt = "%Y-%m-%d %H:%M:%S UTC";
-      } else {
-       tm = localtime(&c.exp);
-       fmt = "%Y-%m-%d %H:%M:%S %Z";
-      }
-      strftime(buf, sizeof(buf), fmt, tm);
-    }
-    printf("INFO keyid = %08lx; expiry = %s\n", (unsigned long)c.k, buf);
-  }
-
-  /* --- Check the authentication token width --- */
-
-  cbits = (d.len - COOKIE_SZ) * 8;
-  if (v > 2) printf("INFO authentication token width = %i bits\n", cbits);
-  if (bits == -1) {
-    if (cbits < minbits) {
-      if (v) printf("FAIL authentication token too narrow\n");
-      goto fail;
-    }
-  } else {
-    if (cbits != bits) {
-      if (v) printf("FAIL authentication token width doesn't match\n");
-      goto fail;
-    }
-  }
-  /* --- Get the key --- */
-
-  if ((k = key_byid(&f, c.k)) == 0) {
-    if (v) printf("FAIL keyid %08lx unavailable\n", (unsigned long)c.k);
-    goto fail;
-  }
-
-  /* --- Check that the cookie authenticates OK --- */
-
-  m = getmac(k, "cookie");
-  h = GM_INIT(m);
-  GH_HASH(h, d.buf, COOKIE_SZ);
-  if (argv[optind + 1])
-    GH_HASH(h, argv[optind + 1], strlen(argv[optind + 1]));
-  t = GH_DONE(h, 0);
-
-  if (memcmp(t, d.buf + COOKIE_SZ, cbits / 8) != 0) {
-    if (v) printf("FAIL bad authentication token\n");
-    goto fail;
-  }
-
-  /* --- See whether the cookie has expired --- */
-
-  if (c.exp == KEXP_FOREVER) {
-    if (!(fl & f_forever)) {
-      if (v) printf("FAIL forever cookies not allowed\n");
-      goto fail;
-    }
-    if (k->exp != KEXP_FOREVER) {
-      if (v) printf("FAIL cookie lasts forever but key will expire\n");
-      goto fail;
-    }
-  } else if (c.exp < now) {
-    if (v) printf("FAIL cookie has expired\n");
-    goto fail;
-  }
-
-  if (v) printf("OK\n");
-  key_close(&f);
-  GM_DESTROY(m);
-  GH_DESTROY(h);
-  dstr_destroy(&d);
-  return (0);
-
-fail:
-  key_close(&f);
-  dstr_destroy(&d);
-  return (1);
-
-#undef f_bogus
-#undef f_forever
-#undef f_utc
-}
-
-/*----- Main command table ------------------------------------------------*/
-
-static int cmd_help(int, char **);
-
-#define LISTS(LI)                                                      \
-  LI("Lists", list,                                                    \
-     listtab[i].name, listtab[i].name)                                 \
-  LI("Message authentication algorithms", mac,                         \
-     gmactab[i], gmactab[i]->name)
-
-MAKELISTTAB(listtab, LISTS)
-
-static int cmd_show(int argc, char *argv[])
-{
-  return (displaylists(listtab, argv + 1));
-}
-
-static cmd cmds[] = {
-  { "help", cmd_help, "help [COMMAND...]" },
-  { "show", cmd_show, "show [ITEM...]" },
-  { "generate", cmd_gen,
-    "generate [-b BITS] [-e TIME] [-k TAG] [DATA]", "\
-Options:\n\
-\n\
--b, --bits=N           Use an N-bit token in the cookie.\n\
--e, --expire=TIME      Make the cookie expire after TIME.\n\
--k, --key=TAG          Use key TAG to create the token.\n\
-" },
-  { "verify", cmd_verify,
-    "verify [-fuqv] [-b BITS] [-m BITS] COOKIE [DATA]", "\
-Options:\n\
-\n\
--b, --bits=N           Accept tokens exactly N bits long only.\n\
--m, --min-bits=N       Accept tokens N bits long or more.\n\
--f, --forever          Accept cookies which never expire.\n\
--u, --utc              Output cookie expiry dates in UTC.\n\
--q, --quiet            Produce less output while checking cookies.\n\
--v, --verbose          Produce more output while checking cookies.\n\
-" },
-  { 0, 0, 0 }
-};
-
-static int cmd_help(int argc, char *argv[])
-{
-  sc_help(cmds, stdout, argv + 1);
-  return (0);
-}
-
-/*----- Main code ---------------------------------------------------------*/
-
-/* --- Helpful GNUy functions --- */
-
-static void usage(FILE *fp)
-{
-  fprintf(fp, "Usage: %s [-k KEYRING] COMMAND [ARGS]\n", QUIS);
-}
-
-void version(FILE *fp)
-{
-  fprintf(fp, "%s, Catacomb version " VERSION "\n", QUIS);
-}
-
-void help_global(FILE *fp)
-{
-  usage(fp);
-  fputs("\n\
-Generates and validates cryptographic cookies.  Command line options\n\
-recognized are:\n\
-\n\
--h, --help [COMMAND]   Display this help text (or help for COMMAND).\n\
--v, --version          Display version number.\n\
--u, --usage            Display short usage summary.\n\
-\n\
--k, --key-file=FILE    Read and write keys in FILE.\n",
-       fp);
-}
-
-/* --- @main@ --- *
- *
- * Arguments:  @int argc@ = number of command line arguments
- *             @char *argv[]@ = array of arguments
- *
- * Returns:    Zero if OK, nonzero if not.
- *
- * Use:                Generates and validates cryptographic cookies.
- */
-
-int main(int argc, char *argv[])
-{
-  unsigned f = 0;
-
-#define f_bogus 1u
-#define f_forever 2u
-
-  /* --- Initialize the library --- */
-
-  ego(argv[0]);
-  sub_init();
-
-  /* --- Options parsing --- */
-
-  for (;;) {
-    static struct option opt[] = {
-
-      /* --- Standard GNUy help options --- */
-
-      { "help",                0,              0,      'h' },
-      { "version",     0,              0,      'v' },
-      { "usage",       0,              0,      'u' },
-
-      /* --- Actual relevant options --- */
-
-      { "keyring",     OPTF_ARGREQ,    0,      'k' },
-
-      /* --- Magic terminator --- */
-
-      { 0,             0,              0,      0 }
-    };
-    int i = mdwopt(argc, argv, "+hvu k:", opt, 0, 0, 0);
-
-    if (i < 0)
-      break;
-    switch (i) {
-
-      /* --- Helpful GNUs --- */
-
-      case 'u':
-       usage(stdout);
-       exit(0);
-      case 'v':
-       version(stdout);
-       exit(0);
-      case 'h':
-       sc_help(cmds, stdout, argv + optind);
-       exit(0);
-
-      /* --- Real genuine useful options --- */
-
-      case 'k':
-       keyfile = optarg;
-       break;
-
-      /* --- Bogus things --- */
-
-      default:
-       f |= f_bogus;
-       break;
-    }
-  }
-
-  if ((f & f_bogus) || optind == argc) {
-    usage(stderr);
-    exit(EXIT_FAILURE);
-  }
-
-  /* --- Dispatch to appropriate command handler --- */
-
-  argc -= optind;
-  argv += optind;
-  optind = 0;
-  return (findcmd(cmds, argv[0])->cmd(argc, argv));
-
-#undef f_bogus
-#undef f_forever
-}
-
-/*----- That's all, folks -------------------------------------------------*/