From 6a2d21e45b210ca761ff900d9b77625e869524f2 Mon Sep 17 00:00:00 2001 From: mdw Date: Sat, 17 Jun 2000 11:50:53 +0000 Subject: [PATCH] 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. --- pixie.c | 187 +++++++++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 151 insertions(+), 36 deletions(-) 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) -- 2.11.0