safe

Password protected secret keeper
git clone git://git.z3bra.org/safe.git
Log | Files | Refs | README | LICENSE

commit acc0b2109c065f82169563f5390b2d316372e336
parent d29f4d7d42826983eb47319afa94fe4b7af696ca
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:
safe.1 | 6++++--
safe.c | 70+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
2 files changed, 69 insertions(+), 7 deletions(-)

diff --git a/safe.1 b/safe.1 @@ -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 diff --git a/safe.c b/safe.c @@ -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> @@ -18,6 +20,7 @@ #include "arg.h" #include "readpassphrase.h" +#define ASKPASS "thingaskpass" #define MASTER "master" #define SAFE ".secrets" @@ -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;