tMake agent a standalone program - 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 2d6626a1f3a9b271d3e10724254f102de1958013
DIR parent 0f19ce9b57089e25c33edd01d9779b18d3affd41
HTML Author: Willy Goiffon <dev@z3bra.org>
Date: Fri, 7 Jun 2019 12:34:10 +0200
Make agent a standalone program
Diffstat:
M makefile | 23 +++++++++++++++--------
M mkfile | 12 ++++++++++--
A safe-agent.c | 224 +++++++++++++++++++++++++++++++
M safe.c | 70 +++++++------------------------
4 files changed, 265 insertions(+), 64 deletions(-)
---
DIR diff --git a/makefile b/makefile
t@@ -9,19 +9,26 @@ CFLAGS = -Wall -Wextra -pedantic
LDFLAGS = -L/usr/local/lib
LDLIBS = -lsodium
+all: safe safe-agent
+
safe: safe.o readpassphrase.o
+safe-agent: safe-agent.o
clean:
- rm -f *.o safe
+ rm -f *.o safe safe-agent
+
+install: safe safe-agent
+ mkdir -p ${DESTDIR}${PREFIX}/bin
+ cp safe ${DESTDIR}${PREFIX}/bin/safe
+ cp safe-agent ${DESTDIR}${PREFIX}/bin/safe-agent
+ chmod 755 ${DESTDIR}${PREFIX}/bin/safe
+ chmod 755 ${DESTDIR}${PREFIX}/bin/safe-agent
+ mkdir -p ${DESTDIR}${MANPREFIX}/man1
+ cp safe.1 ${DESTDIR}${MANPREFIX}/man1/safe.1
+ chmod 644 ${DESTDIR}${MANPREFIX}/man1/safe.1
-install: safe
- mkdir -p ${DESTDIR}${PREFIX}/bin
- cp safe ${DESTDIR}${PREFIX}/bin/safe
- chmod 755 ${DESTDIR}${PREFIX}/bin/safe
- mkdir -p ${DESTDIR}${MANPREFIX}/man1
- cp safe.1 ${DESTDIR}${MANPREFIX}/man1/safe.1
- chmod 644 ${DESTDIR}${MANPREFIX}/man1/safe.1
uninstall::
rm ${DESTDIR}${PREFIX}/bin/safe
+ rm ${DESTDIR}${PREFIX}/bin/safe-agent
rm ${DESTDIR}${MANPREFIX}/man1/safe.1
DIR diff --git a/mkfile b/mkfile
t@@ -9,23 +9,31 @@ CFLAGS = -g -Wall -Wextra -pedantic
LDFLAGS = -L/usr/local/lib
LDLIBS = -lsodium
+all:V: safe safe-agent
+
safe: safe.o readpassphrase.o
$LD -o $target $prereq $LDFLAGS $LDLIBS
+safe-agent: safe-agent.o
+ $LD -o $target $prereq $LDFLAGS $LDLIBS
+
%.o: %.c
$CC $CPPFLAGS $CFLAGS -c $stem.c
clean:V:
- rm -f *.o safe
+ rm -f *.o safe safe-agent
-install:V: safe
+install:V: safe safe-agent
mkdir -p ${DESTDIR}${PREFIX}/bin
cp safe ${DESTDIR}${PREFIX}/bin/safe
+ cp safe-agent ${DESTDIR}${PREFIX}/bin/safe-agent
chmod 755 ${DESTDIR}${PREFIX}/bin/safe
+ chmod 755 ${DESTDIR}${PREFIX}/bin/safe-agent
mkdir -p ${DESTDIR}${MANPREFIX}/man1
cp safe.1 ${DESTDIR}${MANPREFIX}/man1/safe.1
chmod 644 ${DESTDIR}${MANPREFIX}/man1/safe.1
uninstall:V:
rm ${DESTDIR}${PREFIX}/bin/safe
+ rm ${DESTDIR}${PREFIX}/bin/safe-agent
rm ${DESTDIR}${MANPREFIX}/man1/safe.1
DIR diff --git a/safe-agent.c b/safe-agent.c
t@@ -0,0 +1,224 @@
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sodium.h>
+
+#include "arg.h"
+
+#define SOCKDIR "/tmp/safe-XXXXXX"
+#define SOCKET "agent"
+
+struct safe {
+ int loaded;
+ uint8_t saltkey[crypto_secretstream_xchacha20poly1305_KEYBYTES + crypto_pwhash_SALTBYTES];
+};
+
+int loop = 1;
+char *argv0;
+struct safe s;
+char *sockp = NULL;
+
+void
+usage(void)
+{
+ fprintf(stderr, "usage: %s [-hd] [-t timeout] [-f socket]\n", argv0);
+ exit(1);
+}
+
+char *
+dirname(char *path)
+{
+ static char tmp[PATH_MAX];
+ char *p = NULL;
+ size_t len;
+ snprintf(tmp, sizeof(tmp), "%s", path);
+ len = strlen(tmp);
+ for(p = tmp + len; p > tmp; p--)
+ if(*p == '/')
+ break;
+
+ *p = 0;
+ return tmp;
+}
+
+ssize_t
+xread(int fd, void *buf, size_t nbytes)
+{
+ uint8_t *bp = buf;
+ ssize_t total = 0;
+
+ while (nbytes > 0) {
+ ssize_t n;
+
+ n = read(fd, &bp[total], nbytes);
+ if (n < 0)
+ err(1, "read");
+ else if (n == 0)
+ return total;
+ total += n;
+ nbytes -= n;
+ }
+ return total;
+}
+
+ssize_t
+xwrite(int fd, const void *buf, size_t nbytes)
+{
+ const uint8_t *bp = buf;
+ ssize_t total = 0;
+
+ while (nbytes > 0) {
+ ssize_t n;
+
+ n = write(fd, &bp[total], nbytes);
+ if (n < 0)
+ err(1, "write");
+ else if (n == 0)
+ return total;
+ total += n;
+ nbytes -= n;
+ }
+ return total;
+}
+
+int
+creatsock(char *sockpath)
+{
+ int sfd;
+ struct sockaddr_un addr;
+
+ sfd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sfd < 0)
+ return -1;
+
+ umask(0077);
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ strcpy(addr.sun_path, sockpath);
+
+ if (bind(sfd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
+ return -1;
+
+ if (listen(sfd, 10) < 0)
+ return -1;
+
+ return sfd;
+}
+
+void
+forgetkey()
+{
+ memset(s.saltkey, 0, sizeof(s.saltkey));
+ s.loaded = 0;
+ alarm(0);
+ fprintf(stderr, "memory cleared\n");
+}
+
+void
+sighandler(int signal)
+{
+ switch (signal) {
+ case SIGINT:
+ case SIGTERM:
+ unlink(sockp);
+ rmdir(dirname(sockp));
+ exit(0);
+ /* FALLTHROUGH */
+ case SIGALRM:
+ case SIGUSR1:
+ forgetkey();
+ break;
+ }
+}
+
+int
+servekey(int timeout)
+{
+ int cfd, sfd;
+ ssize_t n;
+
+ sfd = creatsock(sockp);
+ if (sfd < 0)
+ err(1, "%s", sockp);
+
+ s.loaded = 0;
+
+ for (;;) {
+ cfd = accept(sfd, NULL, NULL);
+ if (cfd < 0)
+ err(1, "%s", sockp);
+
+ n = 0;
+ if (s.loaded) {
+ xwrite(cfd, s.saltkey, sizeof(s.saltkey));
+ } else {
+ n = xread(cfd, s.saltkey, sizeof(s.saltkey));
+ if (n == sizeof(s.saltkey)) {
+ s.loaded = 1;
+ alarm(timeout);
+ }
+ }
+ close(cfd);
+ }
+
+ /* NOTREACHED */
+ close(sfd);
+
+ return 0;
+}
+
+int
+main(int argc, char *argv[])
+{
+ pid_t pid;
+ int timeout;
+ size_t dirlen;
+ char path[PATH_MAX] = SOCKDIR;
+
+ pid = getpid();
+
+ ARGBEGIN {
+ case 'f':
+ sockp = EARGF(usage());
+ break;
+ case 't':
+ timeout = atoi(EARGF(usage()));
+ break;
+ default:
+ usage();
+ } ARGEND
+
+ if (sockp) {
+ strncpy(path, sockp, sizeof(path));
+ } else {
+ if (!mkdtemp(path))
+ err(1, "mkdtemp: %s", path);
+
+ dirlen = strnlen(path, sizeof(path));
+ snprintf(path + dirlen, PATH_MAX - dirlen, "/%s.%d", SOCKET, pid);
+ sockp = path;
+ }
+
+ printf("SAFE_PID=%d\n", pid);
+ printf("SAFE_SOCK=%s\n", sockp);
+ printf("export SAFE_PID SAFE_SOCK\n");
+
+ signal(SIGINT, sighandler);
+ signal(SIGTERM, sighandler);
+ signal(SIGUSR1, sighandler);
+ signal(SIGALRM, sighandler);
+
+ return servekey(timeout);
+}
DIR diff --git a/safe.c b/safe.c
t@@ -18,8 +18,6 @@
#include "arg.h"
#include "readpassphrase.h"
-#define SOCKDIR "/tmp/safe-XXXXXX"
-#define SOCKET "agent"
#define MASTER "master"
#define SAFE ".secrets"
t@@ -40,7 +38,7 @@ char *argv0;
void
usage(void)
{
- fprintf(stderr, "usage: %s [-hd] [-s safe] [[-a] entry]\n", argv0);
+ fprintf(stderr, "usage: %s [-h] [-s safe] [[-a] entry]\n", argv0);
exit(1);
}
t@@ -156,61 +154,25 @@ deriv(char *pw, struct safe *s)
}
int
-creatsock(char *sockpath)
+pushkey(struct safe *s, char *path)
{
int sfd;
struct sockaddr_un addr;
- sfd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (sfd < 0)
- return -1;
-
- umask(0077);
- memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
- strcpy(addr.sun_path, sockpath);
+ strcpy(addr.sun_path, path);
- if (bind(sfd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
+ if ((sfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
return -1;
- if (listen(sfd, 10) < 0)
+ if (connect(sfd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
return -1;
- return sfd;
-}
-
-int
-agent(struct safe *s, char *sockp)
-{
- int cfd, sfd;
- pid_t pid;
- size_t dirlen;
- char path[PATH_MAX] = SOCKDIR;
-
- pid = getpid();
-
- if (sockp) {
- strncpy(path, sockp, sizeof(path));
- } else {
- if (!mkdtemp(path))
- err(1, "mkdtemp: %s", path);
-
- dirlen = strnlen(path, sizeof(path));
- snprintf(path + dirlen, PATH_MAX - dirlen, "/%s.%d", SOCKET, pid);
- }
-
- sfd = creatsock(path);
- if (sfd < 0)
- err(1, "%s", path);
-
- printf("SAFE_PID=%d\n", pid);
- printf("SAFE_SOCK=%s\n", path);
+ if (xwrite(sfd, s->salt, sizeof(s->salt)) < 0)
+ return -1;
- while ((cfd = accept(sfd, NULL, NULL)) > 0) {
- xwrite(cfd, s->salt, sizeof(s->salt));
- xwrite(cfd, s->key, sizeof(s->key));
- close(cfd);
- }
+ if (write(sfd, s->key, sizeof(s->key)) < 0)
+ return -1;
close(sfd);
t@@ -354,7 +316,7 @@ readsecret(struct safe *s, int in, int out)
int
main(int argc, char *argv[])
{
- int fd, aflag = 0, dflag = 0;
+ int fd, aflag = 0, pflag = 0;
char *secret = NULL, *sockp = NULL, *safe = SAFE;
struct safe s;
t@@ -364,8 +326,8 @@ main(int argc, char *argv[])
case 'a':
aflag = 1;
break;
- case 'd':
- dflag = 1;
+ case 'p':
+ pflag = 1;
break;
case 's':
safe = EARGF(usage());
t@@ -374,7 +336,7 @@ main(int argc, char *argv[])
usage();
} ARGEND
- if (argc != 1 && !dflag)
+ if (argc != 1 && !pflag)
usage();
if (sodium_init() < 0)
t@@ -391,7 +353,7 @@ main(int argc, char *argv[])
if (fd < 0 && errno != ENOENT)
err(1, "%s", MASTER);
- if (sockp) {
+ if (sockp && !pflag) {
if (readkey(&s, sockp) < 0)
err(1, "%s", sockp);
} else {
t@@ -423,8 +385,8 @@ main(int argc, char *argv[])
}
close(fd);
- if (dflag)
- return agent(&s, sockp);
+ if (pflag)
+ return pushkey(&s, sockp);
secret = argv[0];