From: mdw Date: Sat, 17 Jun 2000 11:50:53 +0000 (+0000) Subject: New pixie protocol allowing application to request passphrases and send X-Git-Url: https://git.distorted.org.uk/u/mdw/catacomb/commitdiff_plain/6a2d21e45b210ca761ff900d9b77625e869524f2 New pixie protocol allowing application to request passphrases and send them to the pixie. Use the secure arena interface for the input buffer. Extend the input buffer. Other minor fixes. --- diff --git a/pixie.c b/pixie.c index a6b7e05..1ee1bab 100644 --- a/pixie.c +++ b/pixie.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: pixie.c,v 1.3 1999/12/22 22:14:40 mdw Exp $ + * $Id: pixie.c,v 1.4 2000/06/17 11:50:53 mdw Exp $ * * Passphrase pixie for Catacomb * @@ -30,6 +30,11 @@ /*----- Revision history --------------------------------------------------* * * $Log: pixie.c,v $ + * Revision 1.4 2000/06/17 11:50:53 mdw + * New pixie protocol allowing application to request passphrases and send + * them to the pixie. Use the secure arena interface for the input + * buffer. Extend the input buffer. Other minor fixes. + * * Revision 1.3 1999/12/22 22:14:40 mdw * Only produce initialization message if verbose. * @@ -83,6 +88,7 @@ #include #include +#include "arena.h" #include "lmem.h" #include "passphrase.h" #include "pixie.h" @@ -97,7 +103,8 @@ static lmem lm; static unsigned flags = 0; enum { - F_SYSLOG = 1 + F_SYSLOG = 1, + F_FETCH = 2 }; /*----- Event logging -----------------------------------------------------*/ @@ -416,7 +423,7 @@ static int p_request(const char *msg, const char *tag, char *buf, size_t sz) dstr_destroy(&d); if (r < 0) goto fail_0; - return (0); + goto ok; /* --- Tidy up when things go wrong --- */ @@ -442,22 +449,47 @@ static int p_request(const char *msg, const char *tag, char *buf, size_t sz) dstr_putf(&d, "%s %s: ", msg, tag); rc = pixie_getpass(d.buf, buf, sz); dstr_destroy(&d); - return (rc); + if (rc) + return (rc); + goto ok; } + + /* --- Sort out the buffer --- * + * + * Strip leading spaces. + */ + +ok: { + char *p = buf; + size_t len; + while (isspace((unsigned char)*p)) + p++; + len = strlen(p); + memmove(buf, p, len); + p[len] = 0; + } + + /* --- Done --- */ + + return (0); } /* --- @p_get@ --- * * - * Arguments: @const char *tag@ = pointer to tag string + * Arguments: @const char **q@ = where to store the result + * @const char *tag@ = pointer to tag string * @unsigned mode@ = reading mode (verify?) * @time_t exp@ = expiry time suggestion * - * Returns: Pointer to passphrase, or zero. + * Returns: Zero if successful, @-1@ on a read failure, or @+1@ if the + * passphrase is missing and there is no fetcher. (This will + * always happen if there is no fetcher and @mode@ is + * @PMODE_VERIFY@. * * Use: Reads a passphrase from somewhere. */ -static const char *p_get(const char *tag, unsigned mode, time_t exp) +static int p_get(const char **q, const char *tag, unsigned mode, time_t exp) { #define LBUFSZ 1024 @@ -469,12 +501,26 @@ static const char *p_get(const char *tag, unsigned mode, time_t exp) if (verbose > 1) log("passphrase `%s' requested", tag); + /* --- If there is no fetcher, life is simpler --- */ + + if (!(flags & F_FETCH)) { + if (mode == PMODE_VERIFY) + return (+1); + if ((p = p_find(tag)) == 0) + return (+1); + *q = p->p; + return (0); + } + /* --- Try to find the phrase --- */ - if ((p = p_find(tag)) == 0) { + if (mode == PMODE_VERIFY) + p_flush(tag); + if (mode == PMODE_VERIFY || (p = p_find(tag)) == 0) { if ((pp = p_alloc(LBUFSZ)) == 0) goto fail; - if (p_request("Passphrase", tag, pp, LBUFSZ) < 0) + if (p_request(mode == PMODE_READ ? "Passphrase" : "New passphrase", + tag, pp, LBUFSZ) < 0) goto fail; p = p_add(tag, pp, exp); if (!p) @@ -502,7 +548,8 @@ static const char *p_get(const char *tag, unsigned mode, time_t exp) memset(pp, 0, LBUFSZ); l_free(&lm, pp); } - return (p->p); + *q = p->p; + return (0); /* --- Tidy up if things went wrong --- */ @@ -524,9 +571,12 @@ typedef struct pixserv { selbuf b; int fd; sel_timer timer; + unsigned f; } pixserv; -#define PIXSERV_TIMEOUT 300 +enum { px_stdin = 1 }; + +#define PIXSERV_TIMEOUT 30 /* --- @pixserv_expire@ --- * * @@ -544,7 +594,7 @@ static void pixserv_expire(struct timeval *tv, void *p) pixserv *px = p; if (px->fd != px->b.reader.fd) close(px->fd); - selbuf_disable(&px->b); + selbuf_destroy(&px->b); close(px->b.reader.fd); DESTROY(px); } @@ -619,18 +669,19 @@ static void pixserv_line(char *s, void *p) /* --- Handle an end-of-file --- */ - sel_rmtimer(&px->timer); + if (!(px->f & px_stdin)) + sel_rmtimer(&px->timer); if (!s) { if (px->fd != px->b.reader.fd) close(px->fd); - selbuf_disable(&px->b); + selbuf_destroy(&px->b); close(px->b.reader.fd); return; } /* --- Fiddle the timeout --- */ - { + if (!(px->f & px_stdin)) { struct timeval tv; gettimeofday(&tv, 0); tv.tv_sec += PIXSERV_TIMEOUT; @@ -654,6 +705,7 @@ INFO LIST\n\ INFO PASS tag [expire]\n\ INFO VERIFY tag [expire]\n\ INFO FLUSH [tag]\n\ +INFO SET tag [expire] -- phrase\n\ INFO QUIT\n\ OK\n\ "); @@ -683,15 +735,26 @@ OK\n\ (mode = PMODE_VERIFY, strcmp(q, "verify") == 0)) { unsigned long t; const char *p; + int rc; if ((q = str_getword(&s)) == 0) pixserv_write(px, "FAIL missing tag\n"); else if ((t = pixserv_timeout(s)) == 0) pixserv_write(px, "FAIL bad timeout\n"); - else if ((p = p_get(q, mode, t > timeout ? timeout : t)) == 0) - pixserv_write(px, "FAIL error reading passphrase\n"); - else - pixserv_write(px, "OK %s\n", p); + else { + rc = p_get(&p, q, mode, t > timeout ? timeout : t); + switch (rc) { + case 0: + pixserv_write(px, "OK %s\n", p); + break; + case -1: + pixserv_write(px, "FAIL error reading passphrase\n"); + break; + case +1: + pixserv_write(px, "MISSING\n"); + break; + } + } } /* --- Flush existing passphrases --- */ @@ -702,11 +765,39 @@ OK\n\ pixserv_write(px, "OK\n"); } + /* --- Set a passphrase --- */ + + else if (strcmp(q, "set") == 0) { + char *tag; + unsigned long t; + if ((tag = str_getword(&s)) == 0) + pixserv_write(px, "FAIL missing tag\n"); + else if ((q = str_getword(&s)) == 0) + pixserv_write(px, "FAIL no passphrase\n"); + else { + if (strcmp(q, "--") != 0) { + t = pixserv_timeout(q); + q = str_getword(&s); + } else + t = pixserv_timeout(0); + if (!q) + pixserv_write(px, "FAIL no passphrase\n"); + else if (strcmp(q, "--") != 0) + pixserv_write(px, "FAIL rubbish found before passphrase\n"); + else { + p_flush(tag); + p_add(tag, s, t); + pixserv_write(px, "OK\n"); + } + } + } + /* --- Shut the server down --- */ else if (strcmp(q, "quit") == 0) { if (verbose) - log("client requested shutdown"); + log("%s client requested shutdown", + px->f & px_stdin ? "local" : "remote"); pixserv_write(px, "OK\n"); exit(0); } @@ -722,12 +813,12 @@ OK\n\ * Arguments: @int fd@ = file descriptor to read from * @int ofd@ = file descriptor to write to * - * Returns: --- + * Returns: Pointer to the new connection. * * Use: Creates a new Pixie server instance for a new connection. */ -static void pixserv_create(int fd, int ofd) +static pixserv *pixserv_create(int fd, int ofd) { pixserv *px = CREATE(pixserv); struct timeval tv; @@ -736,9 +827,13 @@ static void pixserv_create(int fd, int ofd) fdflags(ofd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC); px->fd = ofd; selbuf_init(&px->b, &sel, fd, pixserv_line, px); + px->b.b.a = arena_secure; + selbuf_setsize(&px->b, 1024); gettimeofday(&tv, 0); tv.tv_sec += PIXSERV_TIMEOUT; sel_addtimer(&sel, &px->timer, &tv, pixserv_expire, px); + px->f = 0; + return (px); } /* --- @pixserv_accept@ --- * @@ -934,28 +1029,37 @@ static void pix_setup(struct sockaddr_un *sun, size_t sz) /* --- Variables --- */ -static selbuf c_server, c_client;; +static selbuf c_server, c_client; +static c_flags = 0; +enum { cf_uclose = 1, cf_sclose = 2 }; /* --- Line handler functions --- */ static void c_uline(char *s, void *p) { size_t sz; - if (!s) - exit(0); - sz = strlen(s); - s[sz++] = '\n'; - write(c_server.reader.fd, s, sz); + if (!s) { + selbuf_destroy(&c_client); + shutdown(c_server.reader.fd, 1); + c_flags |= cf_uclose; + } else { + sz = strlen(s); + s[sz++] = '\n'; + write(c_server.reader.fd, s, sz); + } } static void c_sline(char *s, void *p) { if (!s) { - if (verbose > 1) + selbuf_destroy(&c_server); + if (!(c_flags & cf_uclose)) { moan("server closed the connection"); + selbuf_destroy(&c_client); + } exit(0); - } - puts(s); + } else + puts(s); } /* --- @pix_client@ --- * @@ -1048,8 +1152,10 @@ protect important keys. Options provided:\n\ -v, --version Emit more log messages.\n\ -s, --socket=FILE Name the pixie's socket.\n\ -c, --command=COMMAND Shell command to read a passphrase.\n\ +-f, --fetch Fetch passphrases from the terminal.\n\ -t, --timeout=TIMEOUT Length of time to retain a passphrase in memory.\n\ -i, --interactive Allow commands to be typed interactively.\n\ +-d, --daemon Fork into the background after initialization.\n\ -l, --syslog Emit log messages to the system log.\n\ \n\ The COMMAND may contain `%m' and `%t' markers which are replaced by a\n\ @@ -1097,7 +1203,7 @@ int main(int argc, char *argv[]) /* --- Set up the locked memory area --- */ - l_init(&lm, 4096); + l_init(&lm, 16384); setuid(getuid()); /* --- Parse command line arguments --- */ @@ -1118,6 +1224,7 @@ int main(int argc, char *argv[]) { "client", 0, 0, 'C' }, { "socket", OPTF_ARGREQ, 0, 's' }, { "command", OPTF_ARGREQ, 0, 'c' }, + { "fetch", 0, 0, 'f' }, { "timeout", OPTF_ARGREQ, 0, 't' }, { "interactive", 0, 0, 'i' }, { "stdin", 0, 0, 'i' }, @@ -1130,7 +1237,7 @@ int main(int argc, char *argv[]) { 0, 0, 0, 0 } }; - int i = mdwopt(argc, argv, "hVuqvCs:c:t:idl", opts, 0, 0, 0); + int i = mdwopt(argc, argv, "hVuqvCs:c:ft:idl", opts, 0, 0, 0); if (i < 0) break; @@ -1169,6 +1276,10 @@ int main(int argc, char *argv[]) break; case 'c': command = optarg; + flags |= F_FETCH; + break; + case 'f': + flags |= F_FETCH; break; case 'i': f |= f_stdin; @@ -1226,6 +1337,7 @@ int main(int argc, char *argv[]) log("couldn't lock passphrase buffer"); } dstr_destroy(&d); + arena_setsecure(&lm.a); } /* --- Set signal behaviours --- */ @@ -1242,8 +1354,11 @@ int main(int argc, char *argv[]) /* --- Set up the server --- */ pix_setup(sun, sz); - if (f & f_stdin) - pixserv_create(STDIN_FILENO, STDOUT_FILENO); + if (f & f_stdin) { + pixserv *px = pixserv_create(STDIN_FILENO, STDOUT_FILENO); + sel_rmtimer(&px->timer); + px->f |= px_stdin; + } /* --- Fork into the background if requested --- */ @@ -1252,7 +1367,7 @@ int main(int argc, char *argv[]) if (((f & f_stdin) && (isatty(STDIN_FILENO) || isatty(STDOUT_FILENO))) || - !command) + (!command && (flags & F_FETCH))) die(1, "can't become a daemon if terminal required"); if ((kid = fork()) < 0)