commit e6e924374d49aa14e94a28d9b64a9f63bae2426d
parent 31c8d76ff28eee958fdbc3c84918a53040968860
Author: sin <sin@2f30.org>
Date: Mon, 22 Sep 2014 11:27:30 +0100
Add support for encrypted save files
Diffstat:
6 files changed, 276 insertions(+), 23 deletions(-)
diff --git a/Makefile b/Makefile
@@ -3,40 +3,43 @@ include config.mk
.POSIX:
.SUFFIXES: .c .o
-SRC = ratox.c
+HDR = arg.h readpassphrase.h
+LIB = \
+ readpassphrase.o
+SRC = \
+ ratox.c
-OBJ = $(SRC:.c=.o)
+OBJ = $(SRC:.c=.o) $(LIB)
BIN = $(SRC:.c=)
+MAN = $(SRC:.c=.1)
-all: options bin
+all: binlib
-options:
- @echo ratox build options:
- @echo "CFLAGS = $(CFLAGS)"
- @echo "LDFLAGS = $(LDFLAGS)"
- @echo "CC = $(CC)"
+binlib: util.a
+ $(MAKE) bin
bin: $(BIN)
-$(OBJ): config.h config.mk
-
-config.h:
- @echo creating $@ from config.def.h
- @cp config.def.h $@
+$(OBJ): readpassphrase.h config.mk
.o:
@echo LD $@
- @$(LD) -o $@ $< $(LDFLAGS)
+ @$(LD) -o $@ $< util.a $(LDFLAGS)
.c.o:
@echo CC $<
@$(CC) -c -o $@ $< $(CFLAGS)
+util.a: $(LIB)
+ @echo AR $@
+ @$(AR) -r -c $@ $(LIB)
+ @ranlib $@
+
install: all
@echo installing executable to $(DESTDIR)$(PREFIX)/bin
@mkdir -p $(DESTDIR)$(PREFIX)/bin
@cp -f $(BIN) $(DESTDIR)$(PREFIX)/bin
- @chmod 755 $(DESTDIR)$(PREFIX)/bin/$(BIN)
+ @cd $(DESTDIR)$(PREFIX)/bin && chmod 755 $(BIN)
uninstall:
@echo removing executable from $(DESTDIR)$(PREFIX)/bin
@@ -44,4 +47,4 @@ uninstall:
clean:
@echo cleaning
- @rm -f $(BIN) $(OBJ)
+ @rm -f $(BIN) $(OBJ) $(LIB) util.a
diff --git a/config.def.h b/config.def.h
@@ -1,5 +1,7 @@
/* See LICENSE file for copyright and license details. */
+static int encryptsave = 0;
+
static struct node nodes[] = {
{
.addr4 = "192.254.75.98",
diff --git a/config.mk b/config.mk
@@ -9,4 +9,4 @@ CC = cc
LD = $(CC)
CPPFLAGS = -DVERSION=\"${VERSION}\"
CFLAGS = -I/usr/local/include -Wall -Wunused $(CPPFLAGS)
-LDFLAGS = -L/usr/local/lib -ltoxcore
+LDFLAGS = -L/usr/local/lib -ltoxcore -ltoxencryptsave
diff --git a/ratox.c b/ratox.c
@@ -18,9 +18,11 @@
#include <unistd.h>
#include <tox/tox.h>
+#include <tox/toxencryptsave.h>
#include "arg.h"
#include "queue.h"
+#include "readpassphrase.h"
#define LEN(x) (sizeof (x) / sizeof *(x))
#define DATAFILE ".ratox.data"
@@ -161,6 +163,8 @@ static TAILQ_HEAD(reqhead, request) reqhead = TAILQ_HEAD_INITIALIZER(reqhead);
static Tox *tox;
static Tox_Options toxopt;
+static uint8_t *passphrase;
+static uint32_t pplen;
static int running = 1;
static int ipv6;
@@ -176,6 +180,7 @@ static void cbstatusmessage(Tox *, int32_t, const uint8_t *, uint16_t, void *);
static void cbuserstatus(Tox *, int32_t, uint8_t, void *);
static void cbfilecontrol(Tox *, int32_t, uint8_t, uint8_t, uint8_t, const uint8_t *, uint16_t, void *);
static void sendfriendfile(struct friend *);
+static void readpass(void);
static void dataload(void);
static void datasave(void);
static int localinit(void);
@@ -548,6 +553,25 @@ sendfriendtext(struct friend *f)
}
static void
+readpass(void)
+{
+ char pass[BUFSIZ], *p;
+
+ p = readpassphrase("Password: ", pass, sizeof(pass), RPP_ECHO_OFF);
+ if (!p) {
+ perror("readpassphrase");
+ exit(EXIT_FAILURE);
+ }
+ passphrase = malloc(strlen(p)); /* not null-terminated */
+ if (!passphrase) {
+ perror("malloc");
+ exit(EXIT_FAILURE);
+ }
+ memcpy(passphrase, p, strlen(p));
+ pplen = strlen(p);
+}
+
+static void
dataload(void)
{
FILE *fp;
@@ -555,6 +579,9 @@ dataload(void)
uint8_t *data;
int r;
+ if (encryptsave == 1)
+ readpass();
+
fp = fopen(DATAFILE, "r");
if (!fp)
return;
@@ -573,13 +600,20 @@ dataload(void)
fprintf(stderr, "failed to read %s\n", DATAFILE);
exit(EXIT_FAILURE);
}
- r = tox_load(tox, data, sz);
+
+ if (encryptsave == 1)
+ r = tox_encrypted_load(tox, data, sz, passphrase, pplen);
+ else
+ r = tox_load(tox, data, sz);
if (r < 0) {
- fprintf(stderr, "tox_load() failed\n");
+ fprintf(stderr, "%s failed\n",
+ encryptsave == 1 ? "tox_encrypted_load" : "tox_load");
+ exit(EXIT_FAILURE);
+ } else if (r == 1) {
+ fprintf(stderr, "Found encrypted %s but encryption is disabled\n",
+ DATAFILE);
exit(EXIT_FAILURE);
}
- if (r == 1)
- printf("Found encrypted data in %s\n", DATAFILE);
free(data);
fclose(fp);
@@ -598,14 +632,17 @@ datasave(void)
exit(EXIT_FAILURE);
}
- sz = tox_size(tox);
+ sz = encryptsave == 1 ? tox_encrypted_size(tox) : tox_size(tox);
data = malloc(sz);
if (!data) {
perror("malloc");
exit(EXIT_FAILURE);
}
- tox_save(tox, data);
+ if (encryptsave == 1)
+ tox_encrypted_save(tox, data, passphrase, pplen);
+ else
+ tox_save(tox, data);
if (fwrite(data, 1, sz, fp) != sz || ferror(fp)) {
fprintf(stderr, "failed to write %s\n", DATAFILE);
exit(EXIT_FAILURE);
diff --git a/readpassphrase.c b/readpassphrase.c
@@ -0,0 +1,180 @@
+/* $OpenBSD: readpassphrase.c,v 1.24 2013/11/24 23:51:29 deraadt Exp $ */
+
+/*
+ * Copyright (c) 2000-2002, 2007, 2010
+ * Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <pwd.h>
+#include <signal.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include "readpassphrase.h"
+
+static volatile sig_atomic_t signo[_NSIG];
+
+static void handler(int);
+
+char *
+readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
+{
+ ssize_t nr;
+ int input, output, save_errno, i, need_restart;
+ char ch, *p, *end;
+ struct termios term, oterm;
+ struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm;
+ struct sigaction savetstp, savettin, savettou, savepipe;
+
+ /* I suppose we could alloc on demand in this case (XXX). */
+ if (bufsiz == 0) {
+ errno = EINVAL;
+ return(NULL);
+ }
+
+restart:
+ for (i = 0; i < _NSIG; i++)
+ signo[i] = 0;
+ nr = -1;
+ save_errno = 0;
+ need_restart = 0;
+ /*
+ * Read and write to /dev/tty if available. If not, read from
+ * stdin and write to stderr unless a tty is required.
+ */
+ if ((flags & RPP_STDIN) ||
+ (input = output = open(_PATH_TTY, O_RDWR)) == -1) {
+ if (flags & RPP_REQUIRE_TTY) {
+ errno = ENOTTY;
+ return(NULL);
+ }
+ input = STDIN_FILENO;
+ output = STDERR_FILENO;
+ }
+
+ /*
+ * Turn off echo if possible.
+ * If we are using a tty but are not the foreground pgrp this will
+ * generate SIGTTOU, so do it *before* installing the signal handlers.
+ */
+ if (input != STDIN_FILENO && tcgetattr(input, &oterm) == 0) {
+ memcpy(&term, &oterm, sizeof(term));
+ if (!(flags & RPP_ECHO_ON))
+ term.c_lflag &= ~(ECHO | ECHONL);
+ if (term.c_cc[VSTATUS] != _POSIX_VDISABLE)
+ term.c_cc[VSTATUS] = _POSIX_VDISABLE;
+ (void)tcsetattr(input, TCSAFLUSH|TCSASOFT, &term);
+ } else {
+ memset(&term, 0, sizeof(term));
+ term.c_lflag |= ECHO;
+ memset(&oterm, 0, sizeof(oterm));
+ oterm.c_lflag |= ECHO;
+ }
+
+ /*
+ * Catch signals that would otherwise cause the user to end
+ * up with echo turned off in the shell. Don't worry about
+ * things like SIGXCPU and SIGVTALRM for now.
+ */
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0; /* don't restart system calls */
+ sa.sa_handler = handler;
+ (void)sigaction(SIGALRM, &sa, &savealrm);
+ (void)sigaction(SIGHUP, &sa, &savehup);
+ (void)sigaction(SIGINT, &sa, &saveint);
+ (void)sigaction(SIGPIPE, &sa, &savepipe);
+ (void)sigaction(SIGQUIT, &sa, &savequit);
+ (void)sigaction(SIGTERM, &sa, &saveterm);
+ (void)sigaction(SIGTSTP, &sa, &savetstp);
+ (void)sigaction(SIGTTIN, &sa, &savettin);
+ (void)sigaction(SIGTTOU, &sa, &savettou);
+
+ if (!(flags & RPP_STDIN))
+ (void)write(output, prompt, strlen(prompt));
+ end = buf + bufsiz - 1;
+ p = buf;
+ while ((nr = read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r') {
+ if (p < end) {
+ if ((flags & RPP_SEVENBIT))
+ ch &= 0x7f;
+ if (isalpha((unsigned char)ch)) {
+ if ((flags & RPP_FORCELOWER))
+ ch = (char)tolower((unsigned char)ch);
+ if ((flags & RPP_FORCEUPPER))
+ ch = (char)toupper((unsigned char)ch);
+ }
+ *p++ = ch;
+ }
+ }
+ *p = '\0';
+ save_errno = errno;
+ if (!(term.c_lflag & ECHO))
+ (void)write(output, "\n", 1);
+
+ /* Restore old terminal settings and signals. */
+ if (memcmp(&term, &oterm, sizeof(term)) != 0) {
+ while (tcsetattr(input, TCSAFLUSH|TCSASOFT, &oterm) == -1 &&
+ errno == EINTR && !signo[SIGTTOU])
+ continue;
+ }
+ (void)sigaction(SIGALRM, &savealrm, NULL);
+ (void)sigaction(SIGHUP, &savehup, NULL);
+ (void)sigaction(SIGINT, &saveint, NULL);
+ (void)sigaction(SIGQUIT, &savequit, NULL);
+ (void)sigaction(SIGPIPE, &savepipe, NULL);
+ (void)sigaction(SIGTERM, &saveterm, NULL);
+ (void)sigaction(SIGTSTP, &savetstp, NULL);
+ (void)sigaction(SIGTTIN, &savettin, NULL);
+ (void)sigaction(SIGTTOU, &savettou, NULL);
+ if (input != STDIN_FILENO)
+ (void)close(input);
+
+ /*
+ * If we were interrupted by a signal, resend it to ourselves
+ * now that we have restored the signal handlers.
+ */
+ for (i = 0; i < _NSIG; i++) {
+ if (signo[i]) {
+ kill(getpid(), i);
+ switch (i) {
+ case SIGTSTP:
+ case SIGTTIN:
+ case SIGTTOU:
+ need_restart = 1;
+ }
+ }
+ }
+ if (need_restart)
+ goto restart;
+
+ if (save_errno)
+ errno = save_errno;
+ return(nr == -1 ? NULL : buf);
+}
+
+static void handler(int s)
+{
+
+ signo[s] = 1;
+}
diff --git a/readpassphrase.h b/readpassphrase.h
@@ -0,0 +1,31 @@
+/* $OpenBSD: readpassphrase.h,v 1.5 2003/06/17 21:56:23 millert Exp $ */
+
+/*
+ * Copyright (c) 2000, 2002 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+
+#define RPP_ECHO_OFF 0x00 /* Turn off echo (default). */
+#define RPP_ECHO_ON 0x01 /* Leave echo on. */
+#define RPP_REQUIRE_TTY 0x02 /* Fail if there is no tty. */
+#define RPP_FORCELOWER 0x04 /* Force input to lower case. */
+#define RPP_FORCEUPPER 0x08 /* Force input to upper case. */
+#define RPP_SEVENBIT 0x10 /* Strip the high bit from input. */
+#define RPP_STDIN 0x20 /* Read from stdin, not /dev/tty */
+
+char *readpassphrase(const char *, char *, size_t, int);