Split platform compatibility code into compat.c.

Also use getentropy() in entropy.c, since it should be available in all
platforms.

This also cleaned up the error checking in general.
This commit is contained in:
Érico Rolim 2020-11-28 15:27:03 -03:00
parent 4678f8691b
commit 8a6dadd57e
9 changed files with 91 additions and 102 deletions

62
compat.c Normal file
View File

@ -0,0 +1,62 @@
#if defined(HAVE_PIPE2) || defined (HAVE_PROG_INVOCATION)
#define _GNU_SOURCE /* pipe2 or program_invocation_short_name */
#endif /* HAVE_PIPE2 */
/* pipe_cloexec */
#include <unistd.h>
#include <fcntl.h>
/* socket_cloexec */
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
/* program_name */
#include <errno.h>
#include <stdlib.h>
#include "compat.h"
int pipe_cloexec(int fds[2])
{
#ifdef HAVE_PIPE2
// atomic (on newer kernels) application of close-on-exec
if (pipe2(fds, O_CLOEXEC) < 0) {
return 1;
}
#else
// delayed application of close-on-exec
if (pipe(fds) < 0) {
return 1;
}
fcntl(fds[0], F_SETFD, FD_CLOEXEC);
fcntl(fds[1], F_SETFD, FD_CLOEXEC);
#endif /* HAVE_PIPE2 */
return 0;
}
int socket_cloexec(int domain, int type, int protocol)
{
#ifdef HAVE_SOCK_CLOEXEC_H
return socket(domain, (type | SOCK_CLOEXEC), protocol);
#else
int fd = socket(domain, type, protocol);
if (fd < 0) {
return fd;
}
fcntl(fd, F_SETFD, FD_CLOEXEC);
return fd;
#endif /* HAVE_SOCK_CLOEXEC_H */
}
const char *program_name(void)
{
#ifdef HAVE_PROG_INVOCATION
return program_invocation_short_name;
#elif HAVE_GETPROGNAME
return getprogname();
#else
#error "no progname impl"
#endif /* PROG_INVOCATION & GETPROGNAME */
}

8
compat.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef __COMPAT_H_
#define __COMPAT_H_
int pipe_cloexec(int [2]);
int socket_cloexec(int, int, int);
const char *program_name(void);
#endif // __COMPAT_H_

25
configure vendored
View File

@ -5,31 +5,6 @@ ARGS="${CFLAGS} ${LDFLAGS} -x c -o /dev/null -"
printf "" > config.mk
$CC $ARGS <<EOF 2>/dev/null
#include <sys/random.h>
int main() {
ssize_t (*p)(void *, size_t, unsigned int) = getrandom;
}
EOF
[ $? -eq 0 ] && HAVE_GETRANDOM=yes
$CC $ARGS <<EOF 2>/dev/null
#include <stdlib.h>
int main() {
void (*p)(void *, size_t) = arc4random_buf;
}
EOF
[ $? -eq 0 ] && HAVE_ARC4RANDOM=yes
echo "HAVE_GETRANDOM:$HAVE_GETRANDOM"
echo "HAVE_ARC4RANDOM:$HAVE_ARC4RANDOM"
if [ "$HAVE_ARC4RANDOM" ]; then
echo "DEFS += -DHAVE_ARC4RANDOM" >> config.mk
elif [ "$HAVE_GETRANDOM" ]; then
echo "DEFS += -DHAVE_GETRANDOM" >> config.mk
fi
$CC $ARGS <<EOF 2>/dev/null
#define _GNU_SOURCE /* program_invocation_short_name */
#include <errno.h>

View File

@ -16,6 +16,7 @@
* expected by the other PurritoBin clients.
*/
#define _DEFAULT_SOURCE /* getentropy */
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
@ -62,23 +63,15 @@ struct mmap_file encrypt_mmap(struct mmap_file file, uint8_t **keyp, uint8_t **i
return rv;
}
ssize_t err = getrandom(key, KEY_LEN, 0);
if (err != KEY_LEN) {
fputs("getrandom() error!\n", stderr);
if (getentropy(key, KEY_LEN) < 0) {
perror("getentropy()");
return rv;
}
#ifdef RANDOMIZE_IV
#ifdef HAVE_GETRANDOM
err = getrandom(iv, IV_LEN, 0);
if (err != IV_LEN) {
fputs("getrandom() error!\n", stderr);
if (getentropy(iv, IV_LEN) < 0) {
perror("getentropy()");
return rv;
}
#elif HAVE_ARC4RANDOM
arc4random_buf(iv, IV_LEN);
#else
#error "no random buf impl"
#endif /* GETRANDOM & ARC4RANDOM */
memcpy(iv_throwaway, iv, IV_LEN);
#endif /* RANDOMIZE_IV */

View File

@ -12,7 +12,7 @@ LDLIBS += -lbearssl
LDFLAGS += $(CFLAGS) -Wl,--as-needed
PURROBJS = socket.o urls.o files.o comm.o formats.o encrypt.o mmap_file.o
PURROBJS += read_certs.o gemini.o pager.o
PURROBJS += read_certs.o gemini.o pager.o compat.o
LIBSOBJS = $(PURROBJS)

View File

@ -9,8 +9,6 @@ subdir('po')
bearssl = compiler.find_library('bearssl', required: true)
gnu_source = '#define _GNU_SOURCE'
getrandom = compiler.has_header_symbol('sys/random.h', 'getrandom')
arc4random = compiler.has_header_symbol('stdlib.h', 'arc4random')
gnu_progname = compiler.has_header_symbol(
'errno.h',
'program_invocation_short_name',
@ -21,13 +19,6 @@ sock_cloexec = compiler.has_header_symbol('sys/socket.h', 'SOCK_CLOEXEC')
pipe2 = compiler.has_header_symbol('unistd.h', 'pipe2', prefix: gnu_source)
args = []
if arc4random
args += '-DHAVE_ARC4RANDOM'
elif getrandom
args += '-DHAVE_GETRANDOM'
else
error('no random buf impl')
endif
if bsd_progname
args += '-DHAVE_GETPROGNAME'
elif gnu_progname
@ -55,6 +46,7 @@ purrlib = static_library(
'formats.c',
'encrypt.c',
'socket.c',
'compat.c',
)
executable('purr', 'purr.c', link_with: purrlib, dependencies: bearssl, install: true)

19
pager.c
View File

@ -1,7 +1,4 @@
#define _POSIX_C_SOURCE 200112L /* fdopen, nanosleep */
#ifdef HAVE_PIPE2
#define _GNU_SOURCE /* pipe2 */
#endif /* HAVE_PIPE2 */
#include <unistd.h>
#include <stdlib.h>
@ -10,9 +7,9 @@
#include <spawn.h>
#include <time.h>
#include <sys/wait.h>
#include <fcntl.h> /* O_CLOEXEC or fcntl */
#include "pager.h"
#include "compat.h"
int launch_pager(struct pager_proc *p)
{
@ -22,20 +19,10 @@ int launch_pager(struct pager_proc *p)
// using close-on-exec here is safe, because fds created by dup don't
// inherit flags
#ifdef HAVE_PIPE2
// atomic application of close-on-exec
if (pipe2(pipes, O_CLOEXEC) < 0) {
perror("pipe2()");
}
#else
// delayed application of close-on-exec
if (pipe(pipes) < 0) {
perror("pipe()");
if (pipe_cloexec(pipes)) {
perror("pipe_cloexec()");
return rv;
}
fcntl(pipes[0], F_SETFD, FD_CLOEXEC);
fcntl(pipes[1], F_SETFD, FD_CLOEXEC);
#endif /* HAVE_PIPE2 */
char *pager = getenv("PAGER");
if (pager == NULL || *pager == 0) {

31
purr.c
View File

@ -1,10 +1,4 @@
#define _POSIX_C_SOURCE 200112L /* getopt */
#ifdef HAVE_PROG_INVOCATION
#define _GNU_SOURCE /* program_invocation_short_name */
#include <errno.h>
#endif /* HAVE_PROG_INVOCATION */
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
@ -14,28 +8,27 @@
#include <bearssl.h>
#include "purr.h"
#include "compat.h"
#include "mmap_file.h"
#include "read_certs.h"
#include "translation.h"
const char *progname;
__attribute__ ((noreturn))
static void usage(bool fail)
{
char *proghelp;
if (strcmp(progname, "meow") == 0) {
if (strcmp(program_name(), "meow") == 0) {
proghelp = _(
"Usage: meow [options] <file>\n"
" send <file> in encrypted format\n");
} else if (strcmp(progname, "meowd") == 0) {
} else if (strcmp(program_name(), "meowd") == 0) {
proghelp = _(
"Usage meowd [options] <url>\n"
" receive encrypted file from <url>\n");
} else {
proghelp = _(
"Usage: purr [options] <action> <file>|<url>\n"
" action: s[end] | r[ecv]\n");
proghelp = _(
"Usage: purr [options] <action> <file>|<url>\n"
" action: s[end] | r[ecv]\n");
}
FILE *stream = fail ? stderr : stdout;
@ -71,21 +64,13 @@ int main (int argc, char **argv)
bindtextdomain(GETTEXT_PACKAGE, GETTEXT_DIR);
textdomain(GETTEXT_PACKAGE);
#ifdef HAVE_PROG_INVOCATION
progname = program_invocation_short_name;
#elif HAVE_GETPROGNAME
progname = getprogname();
#else
#error "no progname impl"
#endif /* PROG_INVOCATION & GETPROGNAME */
// check program name:
// symlinks to original program with special behavior
if (strcmp(progname, "meow") == 0) {
if (strcmp(program_name(), "meow") == 0) {
// encrypted send mode
send = true;
encrypt = true;
} else if (strcmp(progname, "meowd") == 0) {
} else if (strcmp(program_name(), "meowd") == 0) {
// encrypted recv mode
recv = true;
encrypt = true;

19
urls.c
View File

@ -3,28 +3,18 @@
#include <unistd.h>
#include <stdlib.h>
#ifndef HAVE_SOCK_CLOEXEC_H
#include <fcntl.h>
#endif /* HAVE_SOCK_CLOEXEC_H */
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include "purr.h"
#include "compat.h"
#include "translation.h"
#define MAX_DOMAIN_LEN 254
#define MAX_SHORTY_LEN 16
/* enable atomic close-on-exec for socket */
#ifdef HAVE_SOCK_CLOEXEC_H
#define SOCKET_FLAG SOCK_CLOEXEC
#else
#define SOCKET_FLAG 0
#endif /* HAVE_SOCK_CLOEXEC_H */
static const char *http_sch = "http://";
static const char *https_sch = "https://";
static const char *gemini_sch = "gemini://";
@ -215,14 +205,11 @@ int host_connect(const char *host, const char *port, bool debug)
if (debug) fprintf(stderr, "%s: %s\n", _("IP address"), ip_addr);
// try to establish connection
fd = socket(p->ai_family, p->ai_socktype | SOCKET_FLAG, p->ai_protocol);
fd = socket_cloexec(p->ai_family, p->ai_socktype, p->ai_protocol);
if (fd < 0) {
perror("socket()");
perror("socket_cloexec()");
continue;
}
#ifndef HAVE_SOCK_CLOEXEC_H
fcntl(fd, F_SETFD, FD_CLOEXEC);
#endif /* HAVE_SOCK_CLOEXEC_H */
if (connect(fd, p->ai_addr, p->ai_addrlen) < 0) {
// connect errors can be caused server-side