URI: 
       tPrompt password from an external program when there is no tty - safe - password protected secret keeper
  HTML git clone git://git.z3bra.org/safe.git
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit acc0b2109c065f82169563f5390b2d316372e336
   DIR parent d29f4d7d42826983eb47319afa94fe4b7af696ca
  HTML Author: Willy Goiffon <dev@z3bra.org>
       Date:   Thu, 27 Jun 2019 15:20:11 +0200
       
       Prompt password from an external program when there is no tty
       
       If there is no tty available, the program pointed to by the SAFE_ASKPASS
       environment variable will be called and the password will be read
       from its standard output.
       
       Diffstat:
         M safe.1                              |       6 ++++--
         M safe.c                              |      70 ++++++++++++++++++++++++++++---
       
       2 files changed, 69 insertions(+), 7 deletions(-)
       ---
   DIR diff --git a/safe.1 b/safe.1
       t@@ -83,6 +83,9 @@ Retrieve a secret from your safe
        Defines the location of your safe (default: .secrets)
        .It Ev SAFE_SOCK
        Path to the UNIX-domain socket used to communicate with the agent.
       +.It Ev SAFE_ASKPASS
       +If no TTY is available, the program specified by this variable will be
       +used to read the master password (default: thingaskpass)
        
        .Sh AUTHORS
       -.An Willy Goiffon Aq Mt dev@z3bra.org
       -\ No newline at end of file
       +.An Willy Goiffon Aq Mt dev@z3bra.org
   DIR diff --git a/safe.c b/safe.c
       t@@ -2,11 +2,13 @@
        #include <sys/stat.h>
        #include <sys/types.h>
        #include <sys/un.h>
       +#include <sys/wait.h>
        
        #include <err.h>
        #include <errno.h>
        #include <fcntl.h>
        #include <limits.h>
       +#include <paths.h>
        #include <stdint.h>
        #include <stdio.h>
        #include <stdlib.h>
       t@@ -18,6 +20,7 @@
        #include "arg.h"
        #include "readpassphrase.h"
        
       +#define ASKPASS "thingaskpass"
        #define MASTER  "master"
        #define SAFE    ".secrets"
        
       t@@ -121,14 +124,71 @@ xwrite(int fd, const void *buf, size_t nbytes)
                return total;
        }
        
       +char *
       +spawn_askpass(const char *askpass, const char *msg, char *buf, size_t bufsiz)
       +{
       +        pid_t pid, ret;
       +        int p[2], eof, status;
       +
       +        if (!askpass) {
       +                sodium_memzero(buf, bufsiz);
       +                return buf;
       +        }
       +
       +        if (pipe(p) < 0)
       +                return NULL;
       +
       +        pid = fork();
       +        if (pid < 0)
       +                return NULL;
       +
       +        if (!pid) {
       +                close(p[0]);
       +                if (dup2(p[1], STDOUT_FILENO) < 0)
       +                        return NULL;
       +
       +                execlp(askpass, askpass, msg, NULL);
       +                err(1, "execlp(%s)", askpass); /* NOTREACHED */
       +        }
       +        close(p[1]);
       +
       +        xread(p[0], buf, bufsiz - 1, &eof);
       +        close(p[0]);
       +
       +        ret = waitpid(pid, &status, 0);
       +
       +        if (ret < 0 || !WIFEXITED(status) || WEXITSTATUS(status)) {
       +                sodium_memzero(buf, bufsiz);
       +                return buf;
       +        }
       +
       +        buf[strcspn(buf, "\r\n")] = '\0';
       +        return buf;
       +}
       +
        int
        readpass(const char *prompt, uint8_t **target, size_t *len)
        {
       -        char pass[BUFSIZ], *p;
       -
       -        p = readpassphrase(prompt, pass, sizeof(pass), RPP_ECHO_OFF);
       -        if (!p)
       -                err(1, "readpassphrase:");
       +        int ttyfd;
       +        char pass[BUFSIZ], *askpass, *p;
       +
       +        /*
       +         * read passphrase from an ASKPASS program stdout if there is
       +         * no tty available
       +         */
       +        if ((ttyfd = open(_PATH_TTY, O_RDWR)) < 0) {
       +                askpass = ASKPASS;
       +                if (getenv("SAFE_ASKPASS"))
       +                        askpass = getenv("SAFE_ASKPASS");
       +                p = spawn_askpass(askpass, prompt, pass, sizeof(pass));
       +                if (!p)
       +                        err(1, "askpass:");
       +        } else {
       +                close(ttyfd);
       +                p = readpassphrase(prompt, pass, sizeof(pass), RPP_ECHO_OFF|RPP_REQUIRE_TTY);
       +                if (!p)
       +                        err(1, "readpassphrase:");
       +        }
        
                if (p[0] == '\0')
                        return -1;