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;