From fd75f23b861c315167d60f2546fb3ca342a7bb6f Mon Sep 17 00:00:00 2001 From: Uros Majstorovic Date: Tue, 14 May 2024 23:06:11 +0200 Subject: added server options: daemon mode, log file, drop privileges --- ecp/server/server.c | 358 +++++++++++++++++++++++++++++++++++++--------------- ecp/server/server.h | 5 +- ecp/server/sig.c | 8 +- 3 files changed, 265 insertions(+), 106 deletions(-) diff --git a/ecp/server/server.c b/ecp/server/server.c index 223c548..59b1c60 100644 --- a/ecp/server/server.c +++ b/ecp/server/server.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -22,7 +23,9 @@ #include "server.h" static SRVConfig srv_config; -static const char *srv_llevel_str[] = { +static int proc_forked = 0; +static FILE *log_file = NULL; +static const char *log_level_str[] = { "DEBUG", "INFO", "ERROR" @@ -32,20 +35,6 @@ SRVConfig *srv_get_config(void) { return &srv_config; } -static void usage(char *arg) { - fprintf(stderr, "Usage: %s [ ] [ ]\n", arg); - exit(1); -} - -static void fail(char *format, ...) { - va_list args; - - va_start(args, format); - vfprintf(stderr, format, args); - va_end(args); - exit(1); -} - static void handle_err(ECPConnection *conn, unsigned char mtype, int err) { LOG(LOG_ERR, "handle_err: ctype:%d mtype:%d err:%d\n", conn->type, mtype, err); } @@ -125,23 +114,6 @@ static int conn_auth(ECPSocket *sock, ECPConnection *parent, unsigned char ctype } } -void log_print(int level, char *format, ...) { - va_list args; - time_t t; - char buf[26]; - - if (level >= (sizeof(srv_llevel_str) / sizeof(char *))) return; - - t = time(NULL); - ctime_r(&t, buf); - buf[24] = '\0'; - fprintf(stderr, "%s [%s]: ", buf, srv_llevel_str[level]); - - va_start(args, format); - vfprintf(stderr, format, args); - va_end(args); -} - int ecp_init(ECPContext *ctx, ECPConnHandler *vconn_handler, ECPConnHandler *vlink_handler) { int rv; @@ -157,126 +129,306 @@ int ecp_init(ECPContext *ctx, ECPConnHandler *vconn_handler, ECPConnHandler *vli return ECP_OK; } +void log_vfprintf(int level, FILE *file, char *format, va_list ap) { + time_t t; + char t_buf[26]; + char s_buf[256]; + + if (level >= (sizeof(log_level_str) / sizeof(char *))) return; + + t = time(NULL); + ctime_r(&t, t_buf); + /* terminate before newline */ + t_buf[24] = '\0'; + + vsnprintf(s_buf, sizeof(s_buf), format, ap); + + fprintf(file, "%s [%s]: %s", t_buf, log_level_str[level], s_buf); + fflush(file); +} + +void log_printf(int level, char *format, ...) { + va_list ap; + FILE *file = log_file ? log_file : stderr; + + va_start(ap, format); + log_vfprintf(level, file, format, ap); + va_end(ap); +} + +static void fail(char *format, ...) { + va_list ap; + FILE *file; + + va_start(ap, format); + if (proc_forked) { + file = log_file ? log_file : stderr; + log_vfprintf(LOG_ERR, file, format, ap); + } else { + file = stderr; + vfprintf(file, format, ap); + } + va_end(ap); + fflush(file); + exit(1); +} + +static void usage(char *arg) { + fprintf(stderr, "Usage: %s [options] [ ] [ ]\n", arg); + fprintf(stderr, "Options:\n"); + + fprintf(stderr, "\t-d\n"); + fprintf(stderr, "\t\tdetach\n"); + + fprintf(stderr, "\t-l \n"); + fprintf(stderr, "\t\twrite optput to \n"); + + fprintf(stderr, "\t-u \n"); + fprintf(stderr, "\t\trun as user \n"); + + fprintf(stderr, "\t-g \n"); + fprintf(stderr, "\t\trun as group \n"); + exit(1); +} + +static void daemonize(void) { + pid_t pid; + int null_rd, null_wr; + int rv; + + pid = fork(); + if (pid < 0) fail("fork failed\n"); + if (pid > 0) exit(0); + + proc_forked = 1; + + if (setsid() < 0) fail("setsid failed\n"); + + /* second fork */ + pid = fork(); + if (pid < 0) fail("fork2 failed\n"); + if (pid > 0) exit(0); + + null_rd = open("/dev/null", O_RDONLY); + if (null_rd == -1) fail("open (r) /dev/null failed\n"); + null_wr = open("/dev/null", O_WRONLY); + if (null_wr == -1) fail("open (w) /dev/null failed\n"); + + rv = dup2(null_rd, STDIN_FILENO); + if (rv == -1) fail("dup2 (stdin) failed\n"); + + rv = dup2(null_wr, STDOUT_FILENO); + if (rv == -1) fail("dup2 (stdout) failed\n"); + + rv = dup2(null_wr, STDERR_FILENO); + if (rv == -1) fail("dup2 (stderr) failed\n"); + + close(null_rd); + close(null_wr); +} + int main(int argc, char *argv[]) { - ecp_tr_addr_t addr; + char *endptr; + char *log_fn; + uid_t uid; + gid_t gid; + int detach; + char *init_switch; + ecp_tr_addr_t my_addr; + ECPNode node; ECPContext ctx; ECPSocket sock; ECPConnHandler vconn_handler; ECPConnHandler vlink_handler; - char *endptr; - char *debug_init_str; - int _argc, fd; + int _argi, _argc, fd; int rv; memset(&srv_config, 0, sizeof(srv_config)); + memset(&node, 0, sizeof(node)); + + if (argc < 1) fail("Bad arguments\n"); + + _argc = argc - 1; + _argi = 1; + + log_fn = NULL; + detach = 0; + uid = 0; + gid = 0; + while (_argc && (argv[_argi][0] == '-')) { + switch (argv[_argi][1]) { + case 'd': { + _argi++; + _argc--; + detach = 1; + break; + } + case 'l': { + _argi++; + _argc--; + if (_argc == 0) usage(argv[0]); + log_fn = strdup(argv[_argi]); + _argi++; + _argc--; + break; + } + + case 'u': { + _argi++; + _argc--; + if (_argc == 0) usage(argv[0]); + uid = (uid_t)strtol(argv[_argi], &endptr, 10); + if (endptr[0] != '\0') fail("Bad uid\n"); + _argi++; + _argc--; + break; + } + + case 'g': { + _argi++; + _argc--; + if (_argc == 0) usage(argv[0]); + gid = (gid_t)strtol(argv[_argi], &endptr, 10); + if (endptr[0] != '\0') fail("Bad gid\n"); + _argi++; + _argc--; + break; + } + + default: + usage(argv[0]); + } + } - if (argc < 3) usage(argv[0]); + if (_argc < 4) usage(argv[0]); - _argc = 1; - srv_config.region = (uint8_t)strtol(argv[_argc], &endptr, 16); + srv_config.region = (uint8_t)strtol(argv[_argi], &endptr, 16); if (endptr[0] != '\0') fail("Bad region\n"); if (srv_config.region >= MAX_REGION) fail("Bad region\n"); - _argc++; + _argi++; + _argc--; - srv_config.roles = (uint8_t)strtol(argv[_argc], &endptr, 16); + srv_config.roles = (uint8_t)strtol(argv[_argi], &endptr, 16); if (endptr[0] != '\0') fail("Bad roles\n"); - _argc++; + _argi++; + _argc--; - if (srv_config.roles & ECP_ROLE_DIR) { - if (argc < 7) usage(argv[0]); - } else { - if (argc < 5) usage(argv[0]); - } - - fd = open(argv[_argc], O_RDONLY); - if (fd < 0) fail("Unable to open %s\n", argv[_argc]); + fd = open(argv[_argi], O_RDONLY); + if (fd < 0) fail("Unable to open %s\n", argv[_argi]); rv = ecp_util_read_key(fd, &srv_config.key_perma.public, &srv_config.key_perma.private); close(fd); - if (rv) fail("Unable to read key from %s\n", argv[_argc]); + if (rv) fail("Unable to read key from %s\n", argv[_argi]); srv_config.key_perma.valid = 1; - _argc++; - - rv = ecp_init(&ctx, &vconn_handler, &vlink_handler); - if (rv) fail("ecp_init err:%d\n", rv); - - rv = ecp_sock_create(&sock, &ctx, &srv_config.key_perma); - if (rv) fail("ecp_sock_create err:%d\n", rv); - - rv = ecp_vconn_sock_create(&sock); - if (rv) fail("ecp_vconn_sock_create err:%d\n", rv); + _argi++; + _argc--; - rv = ecp_addr_init(&addr, argv[_argc]); + rv = ecp_addr_init(&my_addr, argv[_argi]); if (rv) fail("ecp_addr_init err:%d\n", rv); - _argc++; - - rv = ecp_sock_open(&sock, &addr); - if (rv) fail("ecp_sock_open err:%d\n", rv); - srv_config.my_addr = addr; + _argi++; + _argc--; rv = acl_init(); if (rv) fail("acl_init err:%d\n", rv); if (srv_config.roles & ECP_ROLE_DIR) { - srv_config.acl_fn_dir = strdup(argv[_argc]); - _argc++; - srv_config.acl_fn = strdup(argv[_argc]); - _argc++; + if (_argc < 2) usage(argv[0]); + + srv_config.acl_fn_dir = strdup(argv[_argi]); + _argi++; + _argc--; + srv_config.acl_fn = strdup(argv[_argi]); + _argi++; + _argc--; rv = acl_load(); if (rv) fail("acl_load err:%d\n", rv); } - rv = sig_init(); - if (rv) fail("sig_init err:%d\n", rv); + if (_argc == 2) { + ecp_ecdh_public_t node_pub; - rv = dir_init(&sock); - if (rv) fail("dir_init err:%d\n", rv); + fd = open(argv[_argi], O_RDONLY); + if (fd < 0) fail("Unable to open %s\n", argv[_argi]); - rv = vlink_init(&sock); - if (rv) fail("vlink_init err:%d\n", rv); + rv = ecp_util_read_key(fd, &node_pub, NULL); + close(fd); + if (rv) fail("Unable to read public key from %s\n", argv[_argi]); + _argi++; + _argc--; - rv = ecp_start_receiver(&sock); - if (rv) fail("ecp_start_receiver err:%d\n", rv); + ecp_node_init(&node, &node_pub, NULL); + + rv = ecp_node_set_addr(&node, argv[_argi]); + if (rv) fail("ecp_node_set_addr err:%d\n", rv); + _argi++; + _argc--; + } else if (_argc) { + usage(argv[0]); + } + + umask(077); /* rw for owner only */ + if (log_fn) { + log_file = fopen(log_fn, "a"); + if (log_file == NULL) fail("Unable to open log file: %s\n", log_fn); + } + + if (detach) daemonize(); + + rv = sig_init(); + if (rv) fail("sig_init err:%d\n", rv); rv = sig_start_handler(&sock); if (rv) fail("sig_start_handler err:%d\n", rv); - if (argc == _argc + 2) { - ECPNode node; - ecp_ecdh_public_t node_pub; - ecp_tr_addr_t node_addr; + rv = ecp_init(&ctx, &vconn_handler, &vlink_handler); + if (rv) fail("ecp_init err:%d\n", rv); - fd = open(argv[_argc], O_RDONLY); - if (fd < 0) fail("Unable to open %s\n", argv[_argc]); + rv = ecp_sock_create(&sock, &ctx, &srv_config.key_perma); + if (rv) fail("ecp_sock_create err:%d\n", rv); - rv = ecp_util_read_key(fd, &node_pub, NULL); - close(fd); - if (rv) fail("Unable to read public key from %s\n", argv[_argc]); - _argc++; + rv = ecp_vconn_sock_create(&sock); + if (rv) fail("ecp_vconn_sock_create err:%d\n", rv); - ecp_node_init(&node, &node_pub, NULL); + rv = ecp_sock_open(&sock, &my_addr); + if (rv) fail("ecp_sock_open err:%d\n", rv); + srv_config.my_addr = my_addr; - rv = ecp_node_set_addr(&node, argv[_argc]); - if (rv) fail("ecp_node_set_addr err:%d\n", rv); - _argc++; + if (uid || gid) { + if (gid) { + rv = setgid(gid); + if (rv) fail("Unable to set group id\n"); + } + if (uid) { + rv = setuid(uid); + if (rv) fail("Unable to set user id\n"); + } + } + + rv = dir_init(&sock); + if (rv) fail("dir_init err:%d\n", rv); + + rv = vlink_init(&sock); + if (rv) fail("vlink_init err:%d\n", rv); + + rv = ecp_start_receiver(&sock); + if (rv) fail("ecp_start_receiver err:%d\n", rv); + if (node.key_perma.valid) { rv = dir_init_ann(&sock, &node); if (rv) fail("dir_init_ann err:%d\n", rv); } - if (_argc != argc) usage(argv[0]); - - debug_init_str = getenv("ECP_DBG_INIT"); - if (debug_init_str) { + init_switch = getenv("ECP_INITSW"); + if (init_switch) { int init_ann; - init_ann = (int)strtol(debug_init_str, &endptr, 10); - if (endptr[0] == '\0') { - LOG(LOG_DEBUG, "init switch start - number of announces:%d\n", init_ann); - dir_init_switch(&sock, init_ann); - LOG(LOG_DEBUG, "init switch done\n"); - } + init_ann = (int)strtol(init_switch, &endptr, 10); + if (endptr[0] != '\0') fail("Bad environment"); + + LOG(LOG_DEBUG, "init switch start - number of announces:%d\n", init_ann); + dir_init_switch(&sock, init_ann); + LOG(LOG_DEBUG, "init switch done\n"); } rv = dir_start_announce(&sock); diff --git a/ecp/server/server.h b/ecp/server/server.h index f8f8cac..652bd04 100644 --- a/ecp/server/server.h +++ b/ecp/server/server.h @@ -5,7 +5,7 @@ #define LOG_ERR 2 #define LOG_LEVEL LOG_DEBUG -#define LOG(l, ...) log_print(l, __VA_ARGS__); +#define LOG(l, ...) log_printf(l, __VA_ARGS__); typedef struct SRVConfig { ECPDHKey key_perma; @@ -17,4 +17,5 @@ typedef struct SRVConfig { } SRVConfig; SRVConfig *srv_get_config(void); -void log_print(int level, char *format, ...); +void log_vfprintf(int level, FILE *file, char *format, va_list ap); +void log_printf(int level, char *format, ...); diff --git a/ecp/server/sig.c b/ecp/server/sig.c index 3b83ade..bf6edbd 100644 --- a/ecp/server/sig.c +++ b/ecp/server/sig.c @@ -35,7 +35,7 @@ static void * _sig_handler(void *arg) { LOG(LOG_ERR, "sig_handler: acl load err:%d\n", rv); continue; } - LOG(LOG_DEBUG, "sig_handler: acl reloaded\n"); + LOG(LOG_DEBUG, "sig_handler: acl reloaded - total keys:%u dir keys:%u\n", acl_count(), acl_dir_count()); break; } @@ -44,6 +44,11 @@ static void * _sig_handler(void *arg) { LOG(LOG_DEBUG, "sig_handler: gc done - inbound connection count:%u\n", ecp_sock_gct_count(sock)); break; } + + default: { + LOG(LOG_DEBUG, "sig_handler: unknown signal:%d\n", sig); + break; + } } } @@ -65,6 +70,7 @@ int sig_init(void) { sigemptyset(&sig_set); sigaddset(&sig_set, SIGUSR1); sigaddset(&sig_set, SIGUSR2); + sigaddset(&sig_set, SIGHUP); rv = pthread_sigmask(SIG_BLOCK, &sig_set, NULL); if (rv) return ECP_ERR; -- cgit v1.2.3