summaryrefslogtreecommitdiff
path: root/ecp/server
diff options
context:
space:
mode:
Diffstat (limited to 'ecp/server')
-rw-r--r--ecp/server/server.c358
-rw-r--r--ecp/server/server.h5
-rw-r--r--ecp/server/sig.c8
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 <time.h>
#include <fcntl.h>
#include <sys/stat.h>
+#include <sys/types.h>
#include <ecp/core.h>
#include <ecp/vconn/vconn.h>
@@ -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 <region> <roles> <private key> <addr> [ <dir acl> <vconn acl> ] [ <public key> <addr> ]\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] <region> <roles> <private key> <addr> [ <dir acl> <vconn acl> ] [ <public key> <addr> ]\n", arg);
+ fprintf(stderr, "Options:\n");
+
+ fprintf(stderr, "\t-d\n");
+ fprintf(stderr, "\t\tdetach\n");
+
+ fprintf(stderr, "\t-l <log file>\n");
+ fprintf(stderr, "\t\twrite optput to <log file>\n");
+
+ fprintf(stderr, "\t-u <uid>\n");
+ fprintf(stderr, "\t\trun as user <uid>\n");
+
+ fprintf(stderr, "\t-g <gid>\n");
+ fprintf(stderr, "\t\trun as group <gid>\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;