ratox

FIFO based tox client
git clone git://git.2f30.org/ratox
Log | Files | Refs | README | LICENSE

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:
MMakefile | 35+++++++++++++++++++----------------
Mconfig.def.h | 2++
Mconfig.mk | 2+-
Mratox.c | 49+++++++++++++++++++++++++++++++++++++++++++------
Areadpassphrase.c | 180+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Areadpassphrase.h | 31+++++++++++++++++++++++++++++++
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);