hashsum.c: Document `--progress' in the `--help' display.
[u/mdw/catacomb] / pixie.c
diff --git a/pixie.c b/pixie.c
index 363f833..af6483a 100644 (file)
--- a/pixie.c
+++ b/pixie.c
@@ -1,13 +1,13 @@
 /* -*-c-*-
  *
- * $Id: pixie.c,v 1.10 2001/02/21 20:03:54 mdw Exp $
+ * $Id$
  *
  * Passphrase pixie for Catacomb
  *
  * (c) 1999 Straylight/Edgeware
  */
 
-/*----- Licensing notice --------------------------------------------------* 
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of Catacomb.
  *
  * it under the terms of the GNU Library 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 Library General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU Library 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.
  */
 
-/*----- Revision history --------------------------------------------------* 
- *
- * $Log: pixie.c,v $
- * Revision 1.10  2001/02/21 20:03:54  mdw
- * Handle select errors (by bombing out).  Cosmetic tweak.
- *
- * Revision 1.9  2001/02/03 16:06:44  mdw
- * Don't set a handler for @SIGINT@ if it's ignored at startup.  Add some
- * error handling for the @select@ loop.
- *
- * Revision 1.8  2001/01/25 22:19:31  mdw
- * Make flags be unsigned.
- *
- * Revision 1.7  2000/12/06 20:33:27  mdw
- * Make flags be macros rather than enumerations, to ensure that they're
- * unsigned.
- *
- * Revision 1.6  2000/10/08 12:06:46  mdw
- * Change size passed to socket function to be a @size_t@.  Insert missing
- * type name for flag declaration.
- *
- * Revision 1.5  2000/07/29 22:05:22  mdw
- * Miscellaneous tidyings:
- *
- *   * Change the timeout to something more appropriate for real use.
- *
- *   * Check assumptions about object types when binding the socket.  In
- *     particular, don't zap the socket if it's really something else.
- *
- *   * In @p_request@, return a failure if the shell command returned
- *     nonzero.  Fix a bug in @p_get@ which incorrectly passes on a success
- *     code when this happens.
- *
- *   * Dispose of the locked memory in client mode to avoid being
- *     antisocial.
- *
- *   * Also in client mode, don't report closure from the server if we're
- *     running noninteractively.
- *
- *   * Insert a missing option letter into the usage string.
- *
- *   * Change to the root directory after forking in daemon mode.
- *
- * 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.
- *
- * Revision 1.2  1999/12/22 22:13:42  mdw
- * Fix bug in passphrase flushing loop.
- *
- * Revision 1.1  1999/12/22 15:58:41  mdw
- * Passphrase pixie support.
- *
- */
-
 /*----- Header files ------------------------------------------------------*/
 
 #include "config.h"
@@ -169,7 +110,7 @@ static void log(const char *p, ...)
     d.len += strftime(d.buf, d.sz, "%Y-%m-%d %H:%M:%S ", tm);
   }
   va_start(ap, p);
-  dstr_vputf(&d, p, ap);
+  dstr_vputf(&d, p, &ap);
   va_end(ap);
 
   if (flags & F_SYSLOG)
@@ -213,7 +154,7 @@ static void p_free(phrase *p)
 {
   if (p->t)
     sel_rmtimer(&p->timer);
-  free(p->tag);
+  xfree(p->tag);
   l_free(&lm, p->p);
   p->next->prev = p->prev;
   p->prev->next = p->next;
@@ -256,7 +197,7 @@ static void *p_alloc(size_t sz)
       return (p);
     if (P_ROOT->next == P_ROOT)
       return (0);
-    if (verbose) { 
+    if (verbose) {
       log("flushing passphrase `%s' to free up needed space",
          P_ROOT->next->tag);
     }
@@ -444,7 +385,7 @@ static int p_request(const char *msg, const char *tag, char *buf, size_t sz)
       if (dup2(fd[1], STDOUT_FILENO) < 0)
        _exit(127);
       close(fd[0]);
-      execl("/bin/sh", "sh", "-c", d.buf, (void *)0);
+      execl("/bin/sh", "sh", "-c", d.buf, (char *)0);
       _exit(127);
     }
 
@@ -655,7 +596,7 @@ static void pixserv_write(pixserv *px, const char *p, ...)
   va_list ap;
 
   va_start(ap, p);
-  dstr_vputf(&d, p, ap);
+  dstr_vputf(&d, p, &ap);
   write(px->fd, d.buf, d.len);
   va_end(ap);
   dstr_destroy(&d);
@@ -684,7 +625,7 @@ static unsigned long pixserv_timeout(const char *p)
     case 'h': t *= 60;
     case 'm': t *= 60;
     case 's': if (q[1] != 0)
-      default:    t = 0;
+      default:   t = 0;
     case 0:   break;
   }
   return (t);
@@ -693,6 +634,7 @@ static unsigned long pixserv_timeout(const char *p)
 /* --- @pixserv_line@ --- *
  *
  * Arguments:  @char *s@ = pointer to the line read
+ *             @size_t len@ = length of the line
  *             @void *p@ = pointer to server block
  *
  * Returns:    ---
@@ -700,7 +642,7 @@ static unsigned long pixserv_timeout(const char *p)
  * Use:                Handles a line read from the client.
  */
 
-static void pixserv_line(char *s, void *p)
+static void pixserv_line(char *s, size_t len, void *p)
 {
   pixserv *px = p;
   char *q, *qq;
@@ -895,7 +837,8 @@ static void pixserv_accept(int fd, unsigned mode, void *p)
   if (mode != SEL_READ)
     return;
   if ((nfd = accept(fd, (struct sockaddr *)&sun, &sunsz)) < 0) {
-    if (verbose)
+    if (verbose && errno != EAGAIN && errno != EWOULDBLOCK &&
+       errno != ECONNABORTED && errno != EPROTO && errno != EINTR)
       log("new connection failed: %s", strerror(errno));
     return;
   }
@@ -1081,24 +1024,23 @@ static unsigned c_flags = 0;
 
 #define cf_uclose 1u
 #define cf_sclose 2u
+#define cf_cooked 4u
 
 /* --- Line handler functions --- */
 
-static void c_uline(char *s, void *p)
+static void c_uline(char *s, size_t len, void *p)
 {
-  size_t 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);
+    s[len++] = '\n';
+    write(c_server.reader.fd, s, len);
   }
 }
 
-static void c_sline(char *s, void *p)
+static void c_sline(char *s, size_t len, void *p)
 {
   if (!s) {
     selbuf_destroy(&c_server);
@@ -1108,7 +1050,22 @@ static void c_sline(char *s, void *p)
     }
     exit(0);
   }
-  puts(s);
+  if (!(c_flags & cf_cooked))
+    puts(s);
+  else {
+    char *q = str_getword(&s);
+    if (strcmp(q, "FAIL") == 0)
+      die(1, "%s", s);
+    else if (strcmp(q, "INFO") == 0 ||
+            strcmp(q, "ITEM") == 0)
+      puts(s);
+    else if (strcmp(q, "OK") == 0) {
+      if (s && *s) puts(s);
+    } else if (strcmp(q, "MISSING") == 0)
+      ;
+    else
+      moan("unexpected output: %s %s", q, s);
+  }
 }
 
 /* --- @pix_client@ --- *
@@ -1152,9 +1109,9 @@ static void pix_client(struct sockaddr_un *sun, size_t sz, char *argv[])
     DPUTC(&d, '\n');
     write(fd, d.buf, d.len);
     shutdown(fd, 1);
-    c_flags |= cf_uclose;
+    c_flags |= cf_uclose | cf_cooked;
     dstr_destroy(&d);
-  } 
+  }
 
   /* --- And repeat --- */
 
@@ -1179,8 +1136,9 @@ static void usage(FILE *fp)
 {
   pquis(fp, "\
 Usage:\n\
-       $ [-qvfidl] [-c command] [-t timeout] [-s socket]\n\
-       $ [-s socket] -C [command args...]\n\
+       $ [-qvfidl] [-c COMMAND] [-t TIMEOUT] [-s SOCKET]\n\
+       $ [-s SOCKET] -C [COMMAND ARGS...]\n\
+       $ [-s SOCKET] -P[P] TAG\n\
 ");
 }
 
@@ -1203,6 +1161,9 @@ protect important keys.  Options provided:\n\
 -u, --usage            Show a (very) terse usage summary.\n\
 \n\
 -C, --client           Connect to a running pixie as a client.\n\
+-P, --passphrase       Request passphrase TAG and print to stdout.\n\
+-PP, --verify-passphrase\n\
+                       Verify passphrase TAG and print to stdout.\n\
 \n\
 -q, --quiet            Emit fewer log messages.\n\
 -v, --version          Emit more log messages.\n\
@@ -1249,6 +1210,8 @@ int main(int argc, char *argv[])
 #define f_stdin 4u
 #define f_daemon 8u
 #define f_syslog 16u
+#define f_fetch 32u
+#define f_verify 64u
 
   /* --- Initialize libraries --- */
 
@@ -1276,6 +1239,8 @@ int main(int argc, char *argv[])
       { "quiet",       0,              0,      'q' },
       { "verbose",     0,              0,      'v' },
       { "client",      0,              0,      'C' },
+      { "passphrase",  0,              0,      'P' },
+      { "verify-passphrase",   0,      0,      '+' },
       { "socket",      OPTF_ARGREQ,    0,      's' },
       { "command",     OPTF_ARGREQ,    0,      'c' },
       { "fetch",       0,              0,      'f' },
@@ -1288,10 +1253,10 @@ int main(int argc, char *argv[])
 
       /* --- Magic terminator --- */
 
-      { 0,             0,              0,      0 }      
+      { 0,             0,              0,      0 }
     };
 
-    int i = mdwopt(argc, argv, "hVuqvCs:c:ft:idl", opts, 0, 0, 0);
+    int i = mdwopt(argc, argv, "hVuqvCPs:c:ft:idl", opts, 0, 0, 0);
     if (i < 0)
       break;
 
@@ -1320,6 +1285,17 @@ int main(int argc, char *argv[])
        break;
       case 'C':
        f |= f_client;
+       f &= ~f_fetch;
+       break;
+      case 'P':
+       if (!(f & f_fetch))
+         f |= f_fetch;
+       else
+         f |= f_verify;
+       break;
+      case '+':
+       f |= f_fetch | f_verify;
+       f &= ~f_client;
        break;
       case 's':
        path = optarg;
@@ -1353,11 +1329,26 @@ int main(int argc, char *argv[])
     }
   }
 
-  if (f & f_bogus || (optind < argc && !(f & f_client))) {
+  if (f & f_bogus ||
+      (optind < argc && !(f & (f_client|f_fetch))) ||
+      ((f & f_fetch) && optind != argc - 1)) {
     usage(stderr);
     exit(1);
   }
 
+  /* --- Handle request for a passphrase --- */
+
+  if (f & f_fetch) {
+    char *buf = l_alloc(&lm, 1024);
+    passphrase_connect(path);
+    if (passphrase_read(argv[optind],
+                       (f & f_verify) ? PMODE_VERIFY : PMODE_READ,
+                       buf, 1024))
+      die(1, "failed to read passphrase: %s", strerror(errno));
+    puts(buf);
+    return (0);
+  }
+
   /* --- Set up the socket address --- */
 
   sun = pixie_address(path, &sz);
@@ -1419,7 +1410,7 @@ int main(int argc, char *argv[])
 
   /* --- Fork into the background if requested --- */
 
-  if (f & f_daemon) {    
+  if (f & f_daemon) {
     pid_t kid;
 
     if (((f & f_stdin) &&
@@ -1443,7 +1434,7 @@ int main(int argc, char *argv[])
     chdir("/");
     setsid();
 
-    if (fork() >= 0)
+    if (fork() != 0)
       _exit(0);
   }