Further work on the client code
Trying to get everything in shape, not looking too bad.
This commit is contained in:
parent
425e2dcd66
commit
983217ffbd
13
Makefile
13
Makefile
@ -1,10 +1,10 @@
|
||||
.PHONY: all clean test testclient install parsers
|
||||
.PHONY: all clean test_s test_c install parsers
|
||||
all: luksrku
|
||||
|
||||
BUILD_REVISION := $(shell git describe --abbrev=10 --dirty --always --tags)
|
||||
INSTALL_PREFIX := /usr/local/
|
||||
CFLAGS := -Wall -Wextra -Wshadow -Wswitch -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Werror=implicit-function-declaration -Werror=format -Wno-unused-parameter
|
||||
CFLAGS += -O3 -std=c11 -pthread -D_POSIX_SOURCE -D_XOPEN_SOURCE=500 -DBUILD_REVISION='"$(BUILD_REVISION)"'
|
||||
CFLAGS += -O3 -std=c11 -pthread -D_POSIX_SOURCE -D_POSIX_C_SOURCE=200112L -D_XOPEN_SOURCE=500 -DBUILD_REVISION='"$(BUILD_REVISION)"'
|
||||
CFLAGS += `pkg-config --cflags openssl`
|
||||
CFLAGS += -ggdb3 -DDEBUG -fsanitize=address -fsanitize=undefined -fsanitize=leak
|
||||
PYPGMOPTS := ../Python/pypgmopts/pypgmopts
|
||||
@ -26,14 +26,11 @@ install: all
|
||||
clean:
|
||||
rm -f $(OBJS) $(OBJS_CFG) luksrku
|
||||
|
||||
test: luksrku
|
||||
test_s: luksrku
|
||||
./luksrku server -vv base
|
||||
|
||||
gdb: luksrku
|
||||
gdb --args ./luksrku -v --server-mode -k server_key.bin
|
||||
|
||||
testclient: luksrku
|
||||
./luksrku -v --client-mode -k client_keys.bin
|
||||
test_c: luksrku
|
||||
./luksrku client -vv export 127.0.0.1
|
||||
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
143
client.c
143
client.c
@ -29,6 +29,10 @@
|
||||
#include <unistd.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
|
||||
|
||||
#include "log.h"
|
||||
#include "openssl.h"
|
||||
@ -36,6 +40,7 @@
|
||||
#include "msg.h"
|
||||
#include "client.h"
|
||||
#include "blacklist.h"
|
||||
#include "keydb.h"
|
||||
|
||||
#if 0
|
||||
static const struct keydb_t *client_keydb;
|
||||
@ -207,6 +212,142 @@ static bool tls_client(const struct keydb_t *keydb, const struct options_t *opti
|
||||
}
|
||||
#endif
|
||||
|
||||
bool keyclient_start(const struct pgmopts_client_t *opts) {
|
||||
struct keyclient_t {
|
||||
const struct pgmopts_client_t *opts;
|
||||
struct keydb_t *keydb;
|
||||
bool volume_unlocked[MAX_VOLUMES_PER_HOST];
|
||||
};
|
||||
|
||||
static int psk_client_callback(SSL *ssl, const EVP_MD *md, const unsigned char **id, size_t *idlen, SSL_SESSION **sess) {
|
||||
fprintf(stderr, "CLIENT CALLBACK\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool contact_keyserver_socket(struct keyclient_t *keyclient, int sd) {
|
||||
struct generic_tls_ctx_t gctx;
|
||||
if (!create_generic_tls_context(&gctx, false)) {
|
||||
log_msg(LLVL_FATAL, "Failed to create OpenSSL client context.");
|
||||
return false;
|
||||
}
|
||||
SSL_CTX_set_psk_use_session_callback(gctx.ctx, psk_client_callback);
|
||||
|
||||
SSL *ssl = SSL_new(gctx.ctx);
|
||||
if (ssl) {
|
||||
SSL_set_fd(ssl, sd);
|
||||
SSL_set_app_data(ssl, keyclient);
|
||||
|
||||
if (SSL_connect(ssl) == 1) {
|
||||
fprintf(stderr, "OK\n");
|
||||
} else {
|
||||
log_openssl(LLVL_FATAL, "SSL_connect failed");
|
||||
}
|
||||
|
||||
} else {
|
||||
log_openssl(LLVL_FATAL, "Cannot establish SSL context when trying to connect to server");
|
||||
}
|
||||
|
||||
SSL_free(ssl);
|
||||
free_generic_tls_context(&gctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool contact_keyserver_ipv4(struct keyclient_t *keyclient, struct sockaddr_in *sockaddr_in, unsigned int port) {
|
||||
sockaddr_in->sin_port = htons(port);
|
||||
|
||||
int sd = socket(sockaddr_in->sin_family, SOCK_STREAM, 0);
|
||||
if (sd == -1) {
|
||||
log_libc(LLVL_ERROR, "Failed to create socket(3)");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (connect(sd, (struct sockaddr*)sockaddr_in, sizeof(struct sockaddr_in)) == -1) {
|
||||
log_libc(LLVL_ERROR, "Failed to connect(3) to %d.%d.%d.%d:%d", PRINTF_FORMAT_IP(sockaddr_in), port);
|
||||
close(sd);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = contact_keyserver_socket(keyclient, sd);
|
||||
|
||||
shutdown(sd, SHUT_RDWR);
|
||||
close(sd);
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool contact_keyserver_hostname(struct keyclient_t *keyclient, const char *hostname) {
|
||||
struct addrinfo hints = {
|
||||
.ai_family = AF_INET,
|
||||
.ai_socktype = SOCK_STREAM,
|
||||
};
|
||||
struct addrinfo *result;
|
||||
int resolve_result = getaddrinfo(hostname, NULL, &hints, &result);
|
||||
if (resolve_result) {
|
||||
log_msg(LLVL_ERROR, "Failed to resolve hostname %s using getaddrinfo(3): %s", hostname, gai_strerror(resolve_result));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (result->ai_addr->sa_family != AF_INET) {
|
||||
freeaddrinfo(result);
|
||||
log_msg(LLVL_ERROR, "getaddrinfo(3) returned non-IPv4 entry");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct sockaddr_in *sin_address = (struct sockaddr_in*)result->ai_addr;
|
||||
log_msg(LLVL_DEBUG, "Resolved %s to %d.%d.%d.%d", hostname, PRINTF_FORMAT_IP(sin_address));
|
||||
|
||||
bool success = contact_keyserver_ipv4(keyclient, sin_address, keyclient->opts->port);
|
||||
|
||||
freeaddrinfo(result);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool keyclient_start(const struct pgmopts_client_t *opts) {
|
||||
/* Load key database first */
|
||||
struct keyclient_t keyclient = {
|
||||
.opts = opts,
|
||||
};
|
||||
bool success = true;
|
||||
|
||||
do {
|
||||
keyclient.keydb = keydb_read(opts->filename);
|
||||
if (!keyclient.keydb) {
|
||||
log_msg(LLVL_FATAL, "Failed to load key database: %s", opts->filename);
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (keyclient.keydb->server_database) {
|
||||
log_msg(LLVL_FATAL, "Not an exported key database: %s -- this database contains LUKS passphrases, refusing to work with it!", opts->filename);
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (keyclient.keydb->host_count != 1) {
|
||||
log_msg(LLVL_FATAL, "Host count %d in %s -- expected exactly one host entry for an exported database.", keyclient.keydb->host_count, opts->filename);
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
struct host_entry_t *host = &keyclient.keydb->hosts[0];
|
||||
if (host->volume_count == 0) {
|
||||
log_msg(LLVL_FATAL, "No volumes found in exported database %s.", opts->filename);
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
log_msg(LLVL_DEBUG, "Attempting to unlock %d volumes of host \"%s\".", host->volume_count, host->host_name);
|
||||
if (opts->hostname) {
|
||||
if (!contact_keyserver_hostname(&keyclient, opts->hostname)) {
|
||||
log_msg(LLVL_ERROR, "Failed to contact key server: %s", opts->hostname);
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* TODO: Loop until keyserver found */
|
||||
}
|
||||
} while (false);
|
||||
|
||||
if (keyclient.keydb) {
|
||||
keydb_free(keyclient.keydb);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
157
server.c
157
server.c
@ -330,92 +330,101 @@ static void client_handler_thread(void *vctx) {
|
||||
struct client_ctx_t *client = (struct client_ctx_t*)vctx;
|
||||
|
||||
SSL *ssl = SSL_new(client->gctx->ctx);
|
||||
SSL_set_fd(ssl, client->fd);
|
||||
SSL_set_app_data(ssl, client);
|
||||
if (ssl) {
|
||||
SSL_set_fd(ssl, client->fd);
|
||||
SSL_set_app_data(ssl, client);
|
||||
|
||||
if (SSL_accept(ssl) <= 0) {
|
||||
ERR_print_errors_fp(stderr);
|
||||
} else {
|
||||
if (client->host) {
|
||||
log_msg(LLVL_DEBUG, "Client \"%s\" connected, sending unlock data for %d volumes.", client->host->host_name, client->host->volume_count);
|
||||
for (unsigned int i = 0; i < client->host->volume_count; i++) {
|
||||
const struct volume_entry_t *volume = &client->host->volumes[i];
|
||||
|
||||
struct msg_t msg = { 0 };
|
||||
memcpy(msg.volume_uuid, volume->volume_uuid, 16);
|
||||
memcpy(msg.luks_passphrase_raw, volume->luks_passphrase_raw, LUKS_PASSPHRASE_RAW_SIZE_BYTES);
|
||||
|
||||
int txlen = SSL_write(ssl, &msg, sizeof(msg));
|
||||
OPENSSL_cleanse(&msg, sizeof(msg));
|
||||
if (txlen != sizeof(msg)) {
|
||||
log_msg(LLVL_WARNING, "Tried to send message of %d bytes, but sent %d. Severing connection to client.", sizeof(msg), txlen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (SSL_accept(ssl) <= 0) {
|
||||
ERR_print_errors_fp(stderr);
|
||||
} else {
|
||||
log_msg(LLVL_FATAL, "Client connected, but no host set.");
|
||||
}
|
||||
}
|
||||
if (client->host) {
|
||||
log_msg(LLVL_DEBUG, "Client \"%s\" connected, sending unlock data for %d volumes.", client->host->host_name, client->host->volume_count);
|
||||
for (unsigned int i = 0; i < client->host->volume_count; i++) {
|
||||
const struct volume_entry_t *volume = &client->host->volumes[i];
|
||||
|
||||
struct msg_t msg = { 0 };
|
||||
memcpy(msg.volume_uuid, volume->volume_uuid, 16);
|
||||
memcpy(msg.luks_passphrase_raw, volume->luks_passphrase_raw, LUKS_PASSPHRASE_RAW_SIZE_BYTES);
|
||||
|
||||
int txlen = SSL_write(ssl, &msg, sizeof(msg));
|
||||
OPENSSL_cleanse(&msg, sizeof(msg));
|
||||
if (txlen != sizeof(msg)) {
|
||||
log_msg(LLVL_WARNING, "Tried to send message of %d bytes, but sent %d. Severing connection to client.", sizeof(msg), txlen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log_msg(LLVL_FATAL, "Client connected, but no host set.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log_openssl(LLVL_FATAL, "Cannot establish SSL context for connecting client");
|
||||
}
|
||||
SSL_free(ssl);
|
||||
shutdown(client->fd, SHUT_RDWR);
|
||||
close(client->fd);
|
||||
}
|
||||
|
||||
bool keyserver_start(const struct pgmopts_server_t *opts) {
|
||||
/* Load key database first */
|
||||
struct keydb_t* keydb = keydb_read(opts->filename);
|
||||
if (!keydb) {
|
||||
log_msg(LLVL_FATAL, "Failed to load key database: %s", opts->filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!keydb->server_database) {
|
||||
log_msg(LLVL_FATAL, "Not a server key database: %s", opts->filename);
|
||||
keydb_free(keydb);
|
||||
return false;
|
||||
}
|
||||
|
||||
struct generic_tls_ctx_t gctx;
|
||||
if (!create_generic_tls_context(&gctx, true)) {
|
||||
log_msg(LLVL_FATAL, "Failed to create OpenSSL server context.");
|
||||
return false;
|
||||
}
|
||||
|
||||
SSL_CTX_set_psk_find_session_callback(gctx.ctx, psk_server_callback);
|
||||
|
||||
int tcp_sock = create_tcp_server_socket(opts->port);
|
||||
if (tcp_sock == -1) {
|
||||
log_msg(LLVL_ERROR, "Cannot start server without server socket.");
|
||||
free_generic_tls_context(&gctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
struct sockaddr_in addr;
|
||||
unsigned int len = sizeof(addr);
|
||||
int client = accept(tcp_sock, (struct sockaddr*)&addr, &len);
|
||||
if (client < 0) {
|
||||
log_libc(LLVL_ERROR, "Unable to accept(2)");
|
||||
close(tcp_sock);
|
||||
free_generic_tls_context(&gctx);
|
||||
return false;
|
||||
bool success = true;
|
||||
struct keydb_t* keydb = NULL;
|
||||
struct generic_tls_ctx_t gctx = { 0 };
|
||||
do {
|
||||
/* Load key database first */
|
||||
keydb = keydb_read(opts->filename);
|
||||
if (!keydb) {
|
||||
log_msg(LLVL_FATAL, "Failed to load key database: %s", opts->filename);
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Client has connected, fire up client thread. */
|
||||
struct client_ctx_t client_ctx = {
|
||||
.gctx = &gctx,
|
||||
.keydb = keydb,
|
||||
.fd = client,
|
||||
};
|
||||
if (!pthread_create_detached_thread(client_handler_thread, &client_ctx, sizeof(client_ctx))) {
|
||||
log_libc(LLVL_FATAL, "Unable to pthread_attr_init(3)");
|
||||
close(tcp_sock);
|
||||
free_generic_tls_context(&gctx);
|
||||
return false;
|
||||
if (!keydb->server_database) {
|
||||
log_msg(LLVL_FATAL, "Not a server key database: %s", opts->filename);
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!create_generic_tls_context(&gctx, true)) {
|
||||
log_msg(LLVL_FATAL, "Failed to create OpenSSL server context.");
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
SSL_CTX_set_psk_find_session_callback(gctx.ctx, psk_server_callback);
|
||||
|
||||
int tcp_sock = create_tcp_server_socket(opts->port);
|
||||
if (tcp_sock == -1) {
|
||||
log_msg(LLVL_ERROR, "Cannot start server without server socket.");
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
struct sockaddr_in addr;
|
||||
unsigned int len = sizeof(addr);
|
||||
int client = accept(tcp_sock, (struct sockaddr*)&addr, &len);
|
||||
if (client < 0) {
|
||||
log_libc(LLVL_ERROR, "Unable to accept(2)");
|
||||
close(tcp_sock);
|
||||
free_generic_tls_context(&gctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Client has connected, fire up client thread. */
|
||||
struct client_ctx_t client_ctx = {
|
||||
.gctx = &gctx,
|
||||
.keydb = keydb,
|
||||
.fd = client,
|
||||
};
|
||||
if (!pthread_create_detached_thread(client_handler_thread, &client_ctx, sizeof(client_ctx))) {
|
||||
log_libc(LLVL_FATAL, "Unable to pthread_attr_init(3)");
|
||||
close(tcp_sock);
|
||||
free_generic_tls_context(&gctx);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} while (false);
|
||||
free_generic_tls_context(&gctx);
|
||||
return true;
|
||||
keydb_free(keydb);
|
||||
return success;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user