#include #include #include #include #include #include #include #include #include #include #include #include #include #include "dir.h" #include "vlink.h" #include "ht.h" #include "acl.h" #include "sig.h" #include "server.h" static SRVConfig srv_config; static int proc_forked = 0; static FILE *log_file = NULL; static const char *log_level_str[] = { "DEBUG", "INFO", "ERROR" }; SRVConfig *srv_get_config(void) { return &srv_config; } 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); } static ECPConnection *conn_new(ECPSocket *sock, ECPConnection *parent, unsigned char ctype) { ECPConnection *conn = NULL; switch (ctype) { case CTYPE_DIR: { if (!(srv_config.roles & ECP_ROLE_DIR)) return NULL; conn = malloc(sizeof(ECPConnection)); if (conn) { ecp_conn_init(conn, sock, ctype); ecp_conn_set_flags(conn, ECP_CONN_FLAG_VBOX); } break; } case ECP_CTYPE_DIR: { if (!(srv_config.roles & ECP_ROLE_DIR)) return NULL; conn = malloc(sizeof(ECPConnection)); if (conn) ecp_conn_init(conn, sock, ctype); break; } case ECP_CTYPE_VCONN: { ECPVConnInb *_conn; if (!(srv_config.roles & ECP_ROLE_VCONN)) return NULL; _conn = malloc(sizeof(ECPVConnInb)); if (_conn) { ecp_vconn_init_inb(_conn, sock); conn = &_conn->b; } break; } case ECP_CTYPE_VLINK: { if (!(srv_config.roles & ECP_ROLE_VCONN)) return NULL; conn = malloc(sizeof(ECPConnection)); if (conn) ecp_vlink_init(conn, sock); break; } } if (conn) ecp_conn_set_flags(conn, ECP_CONN_FLAG_GC); return conn; } static void conn_free(ECPConnection *conn) { free(conn); } static int conn_auth(ECPSocket *sock, ECPConnection *parent, unsigned char ctype, ecp_ecdh_public_t *public) { switch (ctype) { case CTYPE_DIR: { if (public == NULL) return 0; return acl_inlist(public); } case ECP_CTYPE_VLINK: { if (public == NULL) return 0; if (parent == NULL) return acl_inlist(public); return 1; } case ECP_CTYPE_DIR: case ECP_CTYPE_VCONN: return 1; default: return 0; } } int ecp_init(ECPContext *ctx, ECPConnHandler *vconn_handler, ECPConnHandler *vlink_handler) { int rv; rv = ecp_ctx_init(ctx, conn_auth, conn_new, conn_free, handle_err); if (rv) return rv; rv = ecp_vconn_handler_init(ctx, vconn_handler); if (rv) return rv; rv = ecp_vlink_handler_init(ctx, vlink_handler); if (rv) return rv; 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[]) { 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; 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 < 4) usage(argv[0]); 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"); _argi++; _argc--; srv_config.roles = (uint8_t)strtol(argv[_argi], &endptr, 16); if (endptr[0] != '\0') fail("Bad roles\n"); _argi++; _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[_argi]); srv_config.key_perma.valid = 1; _argi++; _argc--; rv = ecp_addr_init(&my_addr, argv[_argi]); if (rv) fail("ecp_addr_init err:%d\n", rv); _argi++; _argc--; rv = acl_init(); if (rv) fail("acl_init err:%d\n", rv); if (srv_config.roles & ECP_ROLE_DIR) { 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); } if (_argc == 2) { ecp_ecdh_public_t node_pub; fd = open(argv[_argi], O_RDONLY); if (fd < 0) fail("Unable to open %s\n", argv[_argi]); 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--; 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); 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); rv = ecp_sock_open(&sock, &my_addr); if (rv) fail("ecp_sock_open err:%d\n", rv); srv_config.my_addr = my_addr; 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); } init_switch = getenv("ECP_INITSW"); if (init_switch) { int init_ann; 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); if (rv) fail("dir_start_announce err:%d\n", rv); rv = vlink_start_keyx(&sock); if (rv) fail("vlink_start_keyx err:%d\n", rv); while(1) pause(); }