URI: 
       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];