X-Git-Url: https://git.distorted.org.uk/~mdw/become/blobdiff_plain/f60a34341fee6aafd5b878dce23b80af7c60064d..1554751791fdc733a5f106915f684a31e419797b:/src/daemon.c diff --git a/src/daemon.c b/src/daemon.c index 8d69510..3320512 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: daemon.c,v 1.12 2003/10/12 00:14:55 mdw Exp $ + * $Id: daemon.c,v 1.18 2004/04/17 10:46:08 mdw Exp $ * * Running a `become' daemon * @@ -26,53 +26,6 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/*----- Revision history --------------------------------------------------* - * - * $Log: daemon.c,v $ - * Revision 1.12 2003/10/12 00:14:55 mdw - * Major overhaul. Now uses DSA signatures rather than the bogus symmetric - * encrypt-and-hope thing. Integrated with mLib and Catacomb. - * - * Revision 1.11 1999/05/04 16:17:12 mdw - * Change to header file name for parser. See log for `parse.h' for - * details. - * - * Revision 1.10 1998/04/23 13:23:09 mdw - * Support new interface to configuration file parser. - * - * Revision 1.9 1998/01/12 16:45:59 mdw - * Fix copyright date. - * - * Revision 1.8 1997/09/26 09:14:58 mdw - * Merged blowfish branch into trunk. - * - * Revision 1.7.2.1 1997/09/26 09:08:05 mdw - * Use the Blowfish encryption algorithm instead of IDEA. This is partly - * because I prefer Blowfish (without any particularly strong evidence) but - * mainly because IDEA is patented and Blowfish isn't. - * - * Revision 1.7 1997/09/17 10:23:23 mdw - * Fix a typo. Port numbers are in network order now, so don't change them. - * - * Revision 1.6 1997/09/09 18:17:06 mdw - * Allow default port to be given as a service name or port number. - * - * Revision 1.5 1997/08/20 16:17:10 mdw - * More sensible restart routine: `_reinit' functions replaced by `_end' and - * `_init' functions. - * - * Revision 1.4 1997/08/07 10:00:37 mdw - * (Log entry for previous version is bogus.) Read netgroups database. - * Give up privileges permanently on startup. - * - * Revision 1.2 1997/08/04 10:24:21 mdw - * Sources placed under CVS control. - * - * Revision 1.1 1997/07/21 13:47:50 mdw - * Initial revision - * - */ - /*----- Header files ------------------------------------------------------*/ /* --- ANSI headers --- */ @@ -110,8 +63,10 @@ /* --- Catacomb headers --- */ #include -#include +#include #include +#include +#include #include #include #include @@ -132,18 +87,18 @@ /*----- Arbitrary constants -----------------------------------------------*/ -#define daemon__awakeEvery (5 * 60) /* Awaken this often to rescan */ +#define daemon__awakeEvery (10) /* Awaken this often to rescan */ /*----- Static variables --------------------------------------------------*/ static int daemon__port = -1; /* No particular port yet */ -static int daemon__readKey = 0; /* Have I read a key? */ -static fwatch daemon__watch; +static fwatch daemon__cwatch, daemon__kwatch; /* Watching key/config files */ static sel_timer daemon__timer; /* Timer for reading */ static sel_state daemon__sel; /* Select context */ static sel_file daemon__listen; /* Listening socket selector */ static const char *daemon__config; /* Configuration file for daemon */ -static dsa_priv daemon__key; /* The key data */ +static const char *daemon__keyfile; /* Keyring file for daemon */ +static gdsa daemon__key; /* The key data */ /*----- Main code ---------------------------------------------------------*/ @@ -176,6 +131,8 @@ void daemon_usePort(int port) static void daemon__moan(const char *f, int line, const char *msg, void *p) { syslog(LOG_ERR, "key file error: %s: %d: %s", f, line, msg); + T( trace(TRACE_DAEMON, "daemon: key file error: %s: %d: %s", + f, line, msg); ) } /* --- @daemon_readKey@ --- * @@ -189,32 +146,95 @@ static void daemon__moan(const char *f, int line, const char *msg, void *p) void daemon_readKey(const char *kf) { - key_packstruct kps[DSA_PRIVFETCHSZ]; key_packdef *kp; key_file f; key *k; int err; + const char *sn; + const char *hn; + const char *errmsg; + gdsa g; - if (daemon__readKey) + if (daemon__keyfile) return; + T( trace(TRACE_DAEMON, "daemon: reading key from `%s'", kf); ) if (key_open(&f, kf, KOPEN_READ, daemon__moan, 0)) - return; - kp = key_fetchinit(dsa_privfetch, kps, &daemon__key); - if ((k = key_bytype(&f, "become-dsa")) == 0) - err = KERR_NOTFOUND; - else - err = key_fetch(kp, k); - if (err) - syslog(LOG_ERR, "couldn't load key: %s", key_strerror(err)); - else { - mp_copy(daemon__key.dp.p); - mp_copy(daemon__key.dp.q); - mp_copy(daemon__key.dp.g); - mp_copy(daemon__key.x); - mp_copy(daemon__key.y); + goto fail_0; + if ((k = key_bytype(&f, "become")) == 0) { + syslog(LOG_ERR, "no key of type `become' found"); + goto fail_1; + } + if ((hn = key_getattr(&f, k, "hash")) == 0) + hn = "sha"; + sn = key_getattr(&f, k, "sig"); + g.r = &rand_global; + if ((g.h = ghash_byname(hn)) == 0) { + syslog(LOG_ERR, "key uses unknown hash algorithm `%s'", hn); + goto fail_1; } + if (!sn || strcmp(sn, "dsa") == 0) { + dh_priv dp; + kp = key_fetchinit(dh_privfetch, 0, &dp); + if ((err = key_fetch(kp, k)) != 0) { + syslog(LOG_ERR, "error loading key: %s", key_strerror(err)); + goto fail_2; + } + if ((g.g = group_prime(&dp.dp)) == 0) { + syslog(LOG_ERR, "bad prime group in key"); + goto fail_3; + } + g.p = G_CREATE(g.g); + if (G_FROMINT(g.g, g.p, dp.y)) { + syslog(LOG_ERR, "bad public key"); + goto fail_4; + } + g.u = mp_copy(dp.x); + } else if (strcmp(sn, "ecdsa") == 0) { + ec_priv ep; + ec_info ei; + kp = key_fetchinit(ec_privfetch, 0, &ep); + if ((err = key_fetch(kp, k)) != 0) { + syslog(LOG_ERR, "error loading key: %s", key_strerror(err)); + goto fail_2; + } + if ((errmsg = ec_getinfo(&ei, ep.cstr)) != 0) { + syslog(LOG_ERR, "bad curve in key: %s", errmsg); + goto fail_3; + } + g.g = group_ec(&ei); + g.p = G_CREATE(g.g); + if (G_FROMEC(g.g, g.p, &ep.p)) { + syslog(LOG_ERR, "bad public point"); + goto fail_4; + } + g.u = mp_copy(ep.x); + } else { + syslog(LOG_ERR, "key uses unknown signature scheme `%s'", sn); + goto fail_1; + } + key_fetchdone(kp); + daemon__keyfile = kf; + key_close(&f); + if (daemon__key.g) { + mp_drop(daemon__key.u); + G_DESTROY(daemon__key.g, daemon__key.p); + G_DESTROYGROUP(daemon__key.g); + } + daemon__key = g; + T( trace(TRACE_DAEMON, "daemon: key read ok"); ) + return; + +fail_4: + G_DESTROY(g.g, g.p); +fail_3: + G_DESTROYGROUP(g.g); +fail_2: key_fetchdone(kp); +fail_1: key_close(&f); +fail_0: + T( trace(TRACE_DAEMON, "daemon: failed to read key"); ) + return; } /* --- @daemon__readConfig@ --- * @@ -230,13 +250,13 @@ static int daemon__readConfig(const char *cf) { FILE *fp; - daemon__readKey = 0; + daemon__keyfile = 0; if ((fp = fopen(cf, "r")) == 0) return (-1); lexer_scan(fp); parse(); fclose(fp); - if (!daemon__readKey) + if (!daemon__keyfile) daemon_readKey(file_KEY); T( trace(TRACE_DAEMON, "daemon: read config file"); ) return (0); @@ -258,15 +278,14 @@ void daemon__read(int fd, unsigned mode, void *p) unsigned char buff[65536]; /* Buffer for incoming packets */ struct sockaddr_in sin; /* Address of packet sender */ char sender[64]; /* Sender's hostname (resolved) */ - octet h[SHA_HASHSZ]; /* Hash of the transmission buffer */ - sha_ctx hc; /* Hashing context */ + ghash *h; /* Hash context */ request rq; /* Request buffer for verification */ ssize_t sz; /* Length of incoming message */ socklen_t slen; /* Length of incoming address */ uint32 u; /* Scratch integer */ uint16 ul; /* And another */ struct hostent *he; /* Resolve structure */ - mp *m, *k, *r, *s; /* Integers for signing */ + gdsa_sig s = GDSA_SIG_INIT; /* Signature block */ int ans; /* Answer from the check */ buf b; /* Buffer for parsing request */ @@ -294,11 +313,19 @@ void daemon__read(int fd, unsigned mode, void *p) syslog(LOG_DEBUG, "packet received from %s", sender); T( trace(TRACE_DAEMON, "daemon: received request from %s", sender); ) + /* --- Sanity check --- */ + + if (!daemon__keyfile) { + syslog(LOG_NOTICE, "no key file: ignoring request"); + T( trace(TRACE_DAEMON, "daemon: no key file: ignoring request"); ) + return; + } + /* --- Unpack the block --- */ rq.host = sin.sin_addr; buf_init(&b, buff, sz); - if (buf_ensure(&b, SHA_HASHSZ)) goto fail; BSTEP(&b, SHA_HASHSZ); + if (buf_ensure(&b, 64)) goto fail; BSTEP(&b, 64); if (buf_getu32(&b, &u)) goto fail; rq.from = u; if (buf_getu32(&b, &u)) goto fail; rq.to = u; if (buf_getu16(&b, &ul) || buf_ensure(&b, ul) || ul >= sizeof(rq.cmd)) @@ -310,9 +337,8 @@ void daemon__read(int fd, unsigned mode, void *p) /* --- Hash the request block --- */ - sha_init(&hc); - sha_hash(&hc, buff, sz); - sha_done(&hc, h); + h = GH_INIT(daemon__key.h); + GH_HASH(h, buff, sz); /* --- Build a reply block --- */ @@ -320,27 +346,20 @@ void daemon__read(int fd, unsigned mode, void *p) syslog(LOG_INFO, "request from %s for %i to become %i to run %s %s", sender, rq.from, rq.to, rq.cmd, ans ? "granted" : "denied"); buf_init(&b, buff, sizeof(buff)); - if (buf_put(&b, h, sizeof(h)) || buf_putbyte(&b, ans)) - goto fail; + buf_put(&b, GH_DONE(h, 0), GH_CLASS(h)->hashsz); + buf_putbyte(&b, ans); + if (BBAD(&b)) goto fail; /* --- Sign the reply block --- */ - sha_init(&hc); - sha_hash(&hc, BBASE(&b), BLEN(&b)); - sha_done(&hc, h); - m = mp_loadb(MP_NEW, h, sizeof(h)); - rand_get(RAND_GLOBAL, h, sizeof(h)); - k = mp_loadb(MP_NEWSEC, h, sizeof(h)); - r = s = MP_NEW; - dsa_mksig(&daemon__key.dp, daemon__key.x, m, k, &r, &s); - buf_putmp(&b, r); - buf_putmp(&b, s); - mp_drop(m); - mp_drop(k); - mp_drop(r); - mp_drop(s); - if (BBAD(&b)) - goto fail; + h = gdsa_beginhash(&daemon__key); + GH_HASH(h, BBASE(&b), BLEN(&b)); + gdsa_endhash(&daemon__key, h); + gdsa_sign(&daemon__key, &s, GH_DONE(h, 0), 0); + GH_DESTROY(h); + buf_putmp(&b, s.r); buf_putmp(&b, s.s); + mp_drop(s.r); mp_drop(s.s); + if (BBAD(&b)) goto fail; /* --- Send the reply off --- */ @@ -408,7 +427,6 @@ static void daemon__rescan(int n, void *p) rule_end(); netg_end(); userdb_end(); - dsa_privfree(&daemon__key); userdb_init(); userdb_local(); userdb_yp(); @@ -419,7 +437,8 @@ static void daemon__rescan(int n, void *p) syslog(LOG_ERR, "error reading configuration file"); sel_rmtimer(&daemon__timer); daemon__setTimer(); - fwatch_update(&daemon__watch, daemon__config); + fwatch_update(&daemon__cwatch, daemon__config); + fwatch_update(&daemon__kwatch, daemon__keyfile); } /* --- @daemon__wakeUp@ --- * @@ -434,22 +453,30 @@ static void daemon__rescan(int n, void *p) static void daemon__wakeUp(struct timeval *tv, void *p) { + T( trace(TRACE_DAEMON, "daemon: interval timer"); ) rand_seed(RAND_GLOBAL, 160); - if (fwatch_update(&daemon__watch, daemon__config)) + daemon__setTimer(); + if (fwatch_update(&daemon__cwatch, daemon__config)) daemon__rescan(0, 0); + else if (fwatch_update(&daemon__kwatch, daemon__keyfile)) { + const char *kf = daemon__keyfile; + daemon__keyfile = 0; + daemon_readKey(kf); + } } /* --- @daemon_init@ --- * * * Arguments: @const char *cf@ = pointer to name of configuration file * @int port@ = port to listen to, or %$-1$% for default + * @unsigned f@ = various flags * * Returns: Never. * * Use: Starts `become' up in daemon mode. */ -void daemon_init(const char *cf, int port) +void daemon_init(const char *cf, int port, unsigned f) { int s; int i; @@ -496,7 +523,8 @@ void daemon_init(const char *cf, int port) if (daemon__readConfig(daemon__config)) die(1, "couldn't read configuration file"); - fwatch_init(&daemon__watch, daemon__config); + fwatch_init(&daemon__cwatch, daemon__config); + fwatch_init(&daemon__kwatch, daemon__keyfile); /* --- Decide on a port to use --- * * @@ -506,9 +534,10 @@ void daemon_init(const char *cf, int port) if (daemon__port == 0) { struct servent *se = getservbyname(quis(), "udp"); - if (!se) - die(1, "no idea which port to listen to"); - daemon__port = se->s_port; + if (se) + daemon__port = se->s_port; + else + daemon__port = htons(SERVER_PORT); } /* --- Now set up a socket --- */ @@ -529,8 +558,7 @@ void daemon_init(const char *cf, int port) /* --- Fork off into the sunset --- */ -#ifdef NDEBUG - { + if (!(f & df_nofork)) { int pid = fork(); FILE *fp; @@ -553,7 +581,6 @@ void daemon_init(const char *cf, int port) } T( trace(TRACE_DAEMON, "daemon: forked to pid %li", (long)getpid()); ) } -#endif /* --- Set signal handlers --- */