summaryrefslogtreecommitdiff
path: root/src/irmd
diff options
context:
space:
mode:
Diffstat (limited to 'src/irmd')
-rw-r--r--src/irmd/CMakeLists.txt18
-rw-r--r--src/irmd/config.h.in7
-rw-r--r--src/irmd/configfile.c115
-rw-r--r--src/irmd/irmd.h2
-rw-r--r--src/irmd/main.c648
-rw-r--r--src/irmd/reg/flow.h3
-rw-r--r--src/irmd/reg/name.c74
-rw-r--r--src/irmd/reg/name.h28
-rw-r--r--src/irmd/reg/reg.c98
-rw-r--r--src/irmd/reg/reg.h6
-rw-r--r--src/irmd/reg/tests/name_test.c51
-rw-r--r--src/irmd/reg/tests/reg_test.c7
-rw-r--r--src/irmd/tests/oap_test.c10
13 files changed, 836 insertions, 231 deletions
diff --git a/src/irmd/CMakeLists.txt b/src/irmd/CMakeLists.txt
index 965c4b3d..46d49391 100644
--- a/src/irmd/CMakeLists.txt
+++ b/src/irmd/CMakeLists.txt
@@ -4,13 +4,14 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})
include_directories(${CMAKE_SOURCE_DIR}/include)
include_directories(${CMAKE_BINARY_DIR}/include)
+set(OUROBOROS_CONFIG_DIR /etc/ouroboros CACHE STRING
+ "Configuration directory")
+
find_library(LIBTOML_LIBRARIES toml QUIET)
if (LIBTOML_LIBRARIES)
set(DISABLE_CONFIGFILE FALSE CACHE BOOL
"Disable configuration file support")
if (NOT DISABLE_CONFIGFILE)
- set(OUROBOROS_CONFIG_DIR /etc/ouroboros/ CACHE STRING
- "Configuration directory")
set(OUROBOROS_CONFIG_FILE irmd.conf CACHE STRING
"Name of the IRMd configuration file")
set(HAVE_TOML TRUE)
@@ -28,7 +29,6 @@ if (LIBTOML_LIBRARIES)
else ()
message(STATUS "Configuration file support disabled by user")
unset(OUROBOROS_CONFIG_FILE CACHE)
- unset(OUROBOROS_CONFIG_DIR CACHE)
set(HAVE_TOML FALSE)
endif ()
else ()
@@ -39,9 +39,19 @@ else ()
unset(HAVE_TOML)
endif ()
+set(OUROBOROS_SECURITY_DIR "${OUROBOROS_CONFIG_DIR}/security" CACHE STRING
+ "Security directory holding authentication information")
+set(OUROBOROS_CA_CRT_DIR "${OUROBOROS_SECURITY_DIR}/cacert" CACHE STRING
+ "Directory holding trusted CA certificates")
+set(OUROBOROS_SRV_CRT_DIR "${OUROBOROS_SECURITY_DIR}/server" CACHE STRING
+ "Directory holding trusted CA certificates")
+set(OUROBOROS_CLI_CRT_DIR "${OUROBOROS_SECURITY_DIR}/client" CACHE STRING
+ "Directory holding trusted CA certificates")
+set(OUROBOROS_UNTRUSTED_DIR "${OUROBOROS_SECURITY_DIR}/untrusted" CACHE STRING
+ "Directory holding untrusted intermediate certificates")
+
set(IRMD_REQ_ARR_TIMEOUT 1000 CACHE STRING
"Timeout for an application to respond to a new flow (ms)")
-
set(BOOTSTRAP_TIMEOUT 5000 CACHE STRING
"Timeout for an IPCP to bootstrap (ms)")
set(ENROLL_TIMEOUT 20000 CACHE STRING
diff --git a/src/irmd/config.h.in b/src/irmd/config.h.in
index 6bf3817b..c829cfb7 100644
--- a/src/irmd/config.h.in
+++ b/src/irmd/config.h.in
@@ -50,7 +50,6 @@
#define IRMD_MIN_THREADS @IRMD_MIN_THREADS@
#define IRMD_ADD_THREADS @IRMD_ADD_THREADS@
-
#cmakedefine HAVE_FUSE
#ifdef HAVE_FUSE
#define FUSE_PREFIX "@FUSE_PREFIX@"
@@ -62,6 +61,12 @@
#define OUROBOROS_CONFIG_FILE "@OUROBOROS_CONFIG_FILE@"
#endif
+#define OUROBOROS_SECURITY_DIR "@OUROBOROS_SECURITY_DIR@"
+#define OUROBOROS_CA_CRT_DIR "@OUROBOROS_CA_CRT_DIR@"
+#define OUROBOROS_SRV_CRT_DIR "@OUROBOROS_SRV_CRT_DIR@"
+#define OUROBOROS_CLI_CRT_DIR "@OUROBOROS_CLI_CRT_DIR@"
+#define OUROBOROS_CHAIN_DIR "@OUROBOROS_UNTRUSTED_DIR@"
+
#define IRMD_PKILL_TIMEOUT @IRMD_PKILL_TIMEOUT@
#cmakedefine IRMD_KILL_ALL_PROCESSES
diff --git a/src/irmd/configfile.c b/src/irmd/configfile.c
index 14b03d53..229a3fd3 100644
--- a/src/irmd/configfile.c
+++ b/src/irmd/configfile.c
@@ -258,7 +258,7 @@ static int toml_dir(toml_table_t * table,
if (!BETWEEN(alpha.u.i,
DHT_ALPHA_MIN, DHT_ALPHA_MAX)) {
log_err("Invalid alpha value: %ld",
- alpha.u.i);
+ (long) alpha.u.i);
return -EINVAL;
}
DHT(conf, alpha) = alpha.u.i;
@@ -268,7 +268,7 @@ static int toml_dir(toml_table_t * table,
if (!BETWEEN(t_expire.u.i,
DHT_T_EXPIRE_MIN, DHT_T_EXPIRE_MAX)) {
log_err("Invalid expire time: %ld",
- t_expire.u.i);
+ (long) t_expire.u.i);
return -EINVAL;
}
DHT(conf, t_expire) = t_expire.u.i;
@@ -278,7 +278,7 @@ static int toml_dir(toml_table_t * table,
if (!BETWEEN(t_refresh.u.i,
DHT_T_REFRESH_MIN, DHT_T_REFRESH_MAX)) {
log_err("Invalid refresh time: %ld",
- t_refresh.u.i);
+ (long) t_refresh.u.i);
return -EINVAL;
}
DHT(conf, t_refresh) = t_refresh.u.i;
@@ -288,7 +288,7 @@ static int toml_dir(toml_table_t * table,
if (!BETWEEN(t_replicate.u.i,
DHT_T_REPLICATE_MIN, DHT_T_REPLICATE_MAX)) {
log_err("Invalid replication time: %ld",
- t_replicate.u.i);
+ (long) t_replicate.u.i);
return -EINVAL;
}
DHT(conf, t_replicate) = t_replicate.u.i;
@@ -297,7 +297,7 @@ static int toml_dir(toml_table_t * table,
if (k.ok) {
if (!BETWEEN(k.u.i, DHT_K_MIN, DHT_K_MAX)) {
log_err("Invalid replication factor: %ld",
- k.u.i);
+ (long) k.u.i);
return -EINVAL;
}
DHT(conf, k) = k.u.i;
@@ -344,7 +344,7 @@ static int toml_routing(toml_table_t * table,
if (t_recalc.ok) {
if (t_recalc.u.i < 1) {
log_err("Invalid ls_t_recalc value: %ld",
- t_recalc.u.i);
+ (long) t_recalc.u.i);
return -EINVAL;
}
conf->routing.ls.t_recalc = t_recalc.u.i;
@@ -353,7 +353,7 @@ static int toml_routing(toml_table_t * table,
if (t_update.ok) {
if (t_update.u.i < 1) {
log_err("Invalid ls_t_update value: %ld",
- t_update.u.i);
+ (long) t_update.u.i);
return -EINVAL;
}
conf->routing.ls.t_update = t_update.u.i;
@@ -362,7 +362,7 @@ static int toml_routing(toml_table_t * table,
if (t_timeo.ok) {
if (t_timeo.u.i < 1) {
log_err("Invalid ls_t_timeo value: %ld",
- t_timeo.u.i);
+ (long) t_timeo.u.i);
return -EINVAL;
}
conf->routing.ls.t_timeo = t_timeo.u.i;
@@ -833,15 +833,27 @@ static int toml_prog_list(toml_array_t * progs,
static int toml_name(toml_table_t * table,
const char * name)
{
- toml_array_t * progs;
- toml_array_t * args;
- toml_datum_t lb;
+ toml_array_t * progs;
+ toml_array_t * args;
+ toml_datum_t lb;
+ toml_datum_t scrt;
+ toml_datum_t skey;
+ toml_datum_t ccrt;
+ toml_datum_t ckey;
+
struct name_info info = {
.pol_lb = LB_SPILL
};
log_dbg("Found service name %s in configuration file.", name);
+ if (strlen(name) > NAME_SIZE) {
+ log_err("Name too long: %s", name);
+ return -1;
+ }
+
+ strcpy(info.name, name);
+
lb = toml_string_in(table, "lb");
if (lb.ok) {
if (strcmp(lb.u.s, "spill") == 0)
@@ -858,7 +870,83 @@ static int toml_name(toml_table_t * table,
return -1;
}
- strcpy(info.name, name);
+ scrt = toml_string_in(table, "server_crt_file");
+ if (scrt.ok) {
+ char * scrt_path = realpath(scrt.u.s, NULL);
+ if (scrt_path == NULL) {
+ log_err("Failed to check path for %s: %s.",
+ scrt.u.s, strerror(errno));
+ free(scrt.u.s);
+ return -1;
+ }
+ if (strlen(scrt.u.s) > NAME_PATH_SIZE) {
+ log_err("Server certificate file path too long: %s",
+ scrt_path);
+ free(scrt.u.s);
+ return -1;
+ }
+ strcpy(info.s.crt, scrt_path);
+ free(scrt_path);
+ free(scrt.u.s);
+ }
+
+ skey = toml_string_in(table, "server_key_file");
+ if (skey.ok) {
+ char * skey_path = realpath(skey.u.s, NULL);
+ if (skey_path == NULL) {
+ log_err("Failed to check path for %s: %s.",
+ skey.u.s, strerror(errno));
+ free(skey.u.s);
+ return -1;
+ }
+ if (strlen(skey.u.s) > NAME_PATH_SIZE) {
+ log_err("Server key file path too long: %s", skey_path);
+ free(skey.u.s);
+ return -1;
+ }
+ strcpy(info.s.key, skey_path);
+ free(skey_path);
+ free(skey.u.s);
+ }
+
+ ccrt = toml_string_in(table, "client_crt_file");
+ if (ccrt.ok) {
+ char * ccrt_path = realpath(ccrt.u.s, NULL);
+ if (ccrt_path == NULL) {
+ log_err("Failed to check path for %s: %s.",
+ ccrt.u.s, strerror(errno));
+ free(ccrt.u.s);
+ return -1;
+ }
+ if (strlen(ccrt.u.s) > NAME_PATH_SIZE) {
+ log_err("Client certificate file path too long: %s",
+ ccrt_path);
+ free(ccrt.u.s);
+ return -1;
+ }
+ strcpy(info.c.crt, ccrt_path);
+ free(ccrt_path);
+ free(ccrt.u.s);
+ }
+
+ ckey = toml_string_in(table, "client_key_file");
+ if (ckey.ok) {
+ char * ckey_path = realpath(ckey.u.s, NULL);
+ if (ckey_path == NULL) {
+ log_err("Failed to check path for %s: %s.",
+ ckey.u.s, strerror(errno));
+ free(ckey.u.s);
+ return -1;
+ }
+ if (strlen(ckey.u.s) > NAME_PATH_SIZE) {
+ log_err("Client key file path too long: %s", ckey_path);
+ free(ckey.u.s);
+ return -1;
+ }
+ strcpy(info.c.key, ckey_path);
+ free(ckey_path);
+ free(ckey.u.s);
+ }
if (name_create(&info) < 0) {
log_err("Failed to create name %s.", name);
@@ -976,7 +1064,8 @@ int irm_configure(const char * path)
rp = realpath(path, NULL);
if (rp == NULL) {
- log_err("Failed to resolve path for %s", path);
+ log_err("Failed to check path for %s: %s.",
+ path, strerror(errno));
goto fail_resolve;
}
diff --git a/src/irmd/irmd.h b/src/irmd/irmd.h
index cf8f6953..3e54904a 100644
--- a/src/irmd/irmd.h
+++ b/src/irmd/irmd.h
@@ -39,7 +39,7 @@ int connect_ipcp(pid_t pid,
const char * component,
qosspec_t qs);
-int name_create(const struct name_info * info);
+int name_create(struct name_info * info);
int name_reg(const char * name,
pid_t pid);
diff --git a/src/irmd/main.c b/src/irmd/main.c
index 4acd0ef3..e799666f 100644
--- a/src/irmd/main.c
+++ b/src/irmd/main.c
@@ -55,6 +55,7 @@
#include "reg/reg.h"
#include "configfile.h"
+#include <dirent.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <signal.h>
@@ -74,6 +75,7 @@
#define IPCP_HASH_LEN(p) hash_len((p)->dir_hash_algo)
#define BIND_TIMEOUT 10 /* ms */
#define TIMESYNC_SLACK 100 /* ms */
+#define OAP_SEEN_TIMER 20 /* s */
#define DEALLOC_TIME 300 /* s */
enum irm_state {
@@ -82,6 +84,13 @@ enum irm_state {
IRMD_SHUTDOWN
};
+struct oaph {
+ struct list_head next;
+
+ uint64_t stamp;
+ uint8_t id[OAP_ID_SIZE];
+};
+
struct cmd {
struct list_head next;
@@ -95,6 +104,12 @@ struct {
#ifdef HAVE_TOML
char * cfg_file; /* configuration file path */
#endif
+ struct {
+ struct auth_ctx * ctx; /* default authentication ctx */
+ struct list_head list; /* OAP headers seen before */
+ pthread_mutex_t mtx; /* mutex for OAP headers */
+ } auth;
+
struct lockfile * lf; /* single irmd per system */
struct shm_rdrbuff * rdrb; /* rdrbuff for packets */
@@ -427,6 +442,65 @@ static int disconnect_ipcp(pid_t pid,
return 0;
}
+static void name_update_sec_paths(struct name_info * info)
+{
+ char * srv_dir = OUROBOROS_SRV_CRT_DIR;
+ char * cli_dir = OUROBOROS_CLI_CRT_DIR;
+
+ assert(info != NULL);
+
+ if (strlen(info->s.crt) == 0)
+ sprintf(info->s.crt, "%s/%s/crt.pem", srv_dir, info->name);
+
+ if (strlen(info->s.key) == 0)
+ sprintf(info->s.key, "%s/%s/key.pem", srv_dir, info->name);
+
+ if (strlen(info->c.crt) == 0)
+ sprintf(info->c.crt, "%s/%s/crt.pem", cli_dir, info->name);
+
+ if (strlen(info->c.key) == 0)
+ sprintf(info->c.key, "%s/%s/key.pem", cli_dir, info->name);
+}
+
+int name_create(struct name_info * info)
+{
+ int ret;
+
+ assert(info != NULL);
+
+ name_update_sec_paths(info);
+
+ ret = reg_create_name(info);
+ if (ret == -EEXIST) {
+ log_info("Name %s already exists.", info->name);
+ return 0;
+ }
+
+ if (ret < 0) {
+ log_err("Failed to create name %s.", info->name);
+ return -1;
+ }
+
+ log_info("Created new name: %s.", info->name);
+
+ return 0;
+}
+
+static int name_destroy(const char * name)
+{
+
+ assert(name != NULL);
+
+ if (reg_destroy_name(name) < 0) {
+ log_err("Failed to destroy name %s.", name);
+ return -1;
+ }
+
+ log_info("Destroyed name: %s.", name);
+
+ return 0;
+}
+
int bind_program(char ** exec,
const char * name,
uint8_t flags)
@@ -450,10 +524,8 @@ int bind_program(char ** exec,
if (!reg_has_name(name)) {
ni.pol_lb = LB_SPILL;
strcpy(ni.name, name);
- if (reg_create_name(&ni) < 0) {
- log_err("Failed to create name %s.", name);
+ if (name_create(&ni) < 0)
goto fail_name;
- }
}
if (reg_bind_prog(name, exec, flags) < 0) {
@@ -499,10 +571,8 @@ int bind_process(pid_t pid,
if (!reg_has_name(name)) {
ni.pol_lb = LB_SPILL;
strcpy(ni.name, name);
- if (reg_create_name(&ni) < 0) {
- log_err("Failed to create name %s.", name);
+ if (name_create(&ni) < 0)
goto fail;
- }
}
if (reg_bind_proc(name, pid) < 0) {
@@ -583,43 +653,6 @@ static int list_ipcps(ipcp_list_msg_t *** ipcps,
return -1;
}
-int name_create(const struct name_info * info)
-{
- int ret;
-
- assert(info != NULL);
-
- ret = reg_create_name(info);
- if (ret == -EEXIST) {
- log_info("Name %s already exists.", info->name);
- return 0;
- }
-
- if (ret < 0) {
- log_err("Failed to create name %s.", info->name);
- return -1;
- }
-
- log_info("Created new name: %s.", info->name);
-
- return 0;
-}
-
-static int name_destroy(const char * name)
-{
-
- assert(name != NULL);
-
- if (reg_destroy_name(name) < 0) {
- log_err("Failed to destroy name %s.", name);
- return -1;
- }
-
- log_info("Destroyed name: %s.", name);
-
- return 0;
-}
-
static int list_names(name_info_msg_t *** names,
size_t * n_names)
{
@@ -762,22 +795,244 @@ static void __cleanup_flow(void * flow)
reg_destroy_flow(((struct flow_info *) flow)->id);
}
+static bool file_exists(const char * path)
+{
+ struct stat s;
+
+ if (stat(path, &s) < 0 && errno == ENOENT) {
+ log_dbg("File %s does not exist.", path);
+ return false;
+ }
+
+ return true;
+}
+
+static int load_credentials(const char * name,
+ const struct name_sec_paths * paths,
+ void ** pkp,
+ void ** crt)
+{
+ assert(paths != NULL);
+ assert(pkp != NULL);
+ assert(crt != NULL);
+
+ *pkp = NULL;
+ *crt = NULL;
+
+ if (!file_exists(paths->crt) || !file_exists(paths->key)) {
+ log_info("No security info for %s.", name);
+ return 0;
+ }
+
+ if (crypt_load_crt_file(paths->crt, crt) < 0) {
+ log_err("Failed to load %s for %s.", paths->crt, name);
+ goto fail_crt;
+ }
+
+ if (crypt_load_privkey_file(paths->key, pkp) < 0) {
+ log_err("Failed to load %s for %s.", paths->key, name);
+ goto fail_key;
+ }
+
+ log_info("Loaded security keys for %s.", name);
+
+ return 0;
+
+ fail_key:
+ crypt_free_crt(*crt);
+ *crt = NULL;
+ fail_crt:
+ return -EAUTH;
+}
+
+static int load_srv_credentials(const char * name,
+ void ** pkp,
+ void ** crt)
+{
+ struct name_info info;
+
+ assert(name != NULL);
+ assert(pkp != NULL);
+ assert(crt != NULL);
+
+ if (reg_get_name_info(name, &info) < 0) {
+ log_err("Failed to get name info for %s.", name);
+ return -ENAME;
+ }
+
+ return load_credentials(name, &info.s, pkp, crt);
+}
+
+static int load_cli_credentials(const char * name,
+ void ** pkp,
+ void ** crt)
+{
+ struct name_info info;
+
+ assert(name != NULL);
+ assert(pkp != NULL);
+ assert(crt != NULL);
+
+ if (reg_get_name_info(name, &info) < 0) {
+ log_err("Failed to get name info for %s.", name);
+ return -ENAME;
+ }
+
+ return load_credentials(name, &info.c, pkp, crt);
+}
+
+#define ID_IS_EQUAL(id1, id2) (memcmp(id1, id2, OAP_ID_SIZE) == 0)
+static int irm_check_oap_hdr(const struct oap_hdr * oap_hdr,
+ time_t mpl)
+{
+ struct list_head * p;
+ struct list_head * h;
+ struct timespec now;
+ struct oaph * new;
+ uint64_t stamp;
+ uint64_t cur;
+ uint8_t * id;
+ ssize_t delta;
+
+ assert(oap_hdr != NULL);
+
+ stamp = oap_hdr->timestamp;
+ id = oap_hdr->id.data;
+
+ clock_gettime(CLOCK_REALTIME, &now);
+
+ cur = TS_TO_UINT64(now);
+
+ delta = (ssize_t)(cur - stamp) / MILLION;
+ if (delta > mpl)
+ log_warn("Transit time exceeds MPL by %zd ms.", delta);
+ if (delta < -TIMESYNC_SLACK)
+ log_warn("OAP header sent %zd ms from the future.", -delta);
+
+ new = malloc(sizeof(*new));
+ if (new == NULL) {
+ log_err("Failed to allocate memory for OAP element.");
+ return -ENOMEM;
+ }
+
+ pthread_mutex_lock(&irmd.auth.mtx);
+
+ list_for_each_safe(p, h, &irmd.auth.list) {
+ struct oaph * oaph = list_entry(p, struct oaph, next);
+ if (cur > oaph->stamp + OAP_SEEN_TIMER * BILLION) {
+ list_del(&oaph->next);
+ free(oaph);
+ continue;
+ }
+
+ if (oaph->stamp == stamp && ID_IS_EQUAL(oaph->id, id)) {
+ log_warn("OAP header already known: " HASH_FMT64 ".",
+ HASH_VAL64(id));
+ goto fail_replay;
+ }
+ }
+
+ memcpy(new->id, id, OAP_ID_SIZE);
+ new->stamp = stamp;
+
+ list_add_tail(&new->next, &irmd.auth.list);
+
+ pthread_mutex_unlock(&irmd.auth.mtx);
+
+ return 0;
+
+ fail_replay:
+ pthread_mutex_unlock(&irmd.auth.mtx);
+ free(new);
+ return -EAUTH;
+}
+
+static int irm_auth_peer(const char * name,
+ const struct oap_hdr * oap_hdr,
+ const struct oap_hdr * r_oap_hdr)
+{
+ void * crt;
+ void * pk;
+ buffer_t sign;
+
+ if (memcmp(r_oap_hdr->id.data, oap_hdr->id.data, OAP_ID_SIZE) != 0) {
+ log_err("OAP ID mismatch in flow allocation.");
+ goto fail_check;
+ }
+
+ if (r_oap_hdr->crt.len == 0) {
+ log_info("No certificate provided by peer %s.", name);
+ return 0;
+ }
+
+ if (crypt_load_crt_der(r_oap_hdr->crt, &crt) < 0) {
+ log_err("Failed to load certificate from peer %s.", name);
+ goto fail_check;
+ }
+
+ log_dbg("Loaded peer certificate for %s.", name);
+
+ if (crypt_check_crt_name(crt, name) < 0) {
+ log_err("Certificate does not match name %s.", name);
+ goto fail_crt;
+ }
+
+ log_dbg("Certificate matches name %s.", name);
+
+ if (crypt_get_pubkey_crt(crt, &pk) < 0) {
+ log_err("Failed to get pubkey from certificate for %s.", name);
+ goto fail_crt;
+ }
+
+ log_dbg("Got public key from certificate for %s.", name);
+
+ if (auth_verify_crt(irmd.auth.ctx, crt) < 0) {
+ log_err("Failed to verify peer %s with CA store.", name);
+ goto fail_crt;
+ }
+
+ log_info("Successfully verified peer certificate for %s.", name);
+
+ sign = r_oap_hdr->hdr;
+ sign.len -= (r_oap_hdr->sig.len + sizeof(uint16_t));
+
+ if (auth_verify_sig(pk, sign, r_oap_hdr->sig) < 0) {
+ log_err("Failed to verify signature for peer %s.", name);
+ goto fail_check_sig;
+ }
+
+ crypt_free_key(pk);
+ crypt_free_crt(crt);
+
+ log_info("Successfully authenticated %s.", name);
+
+ return 0;
+
+ fail_check_sig:
+ crypt_free_key(pk);
+ fail_crt:
+ crypt_free_crt(crt);
+ fail_check:
+ return -1;
+}
+
static int flow_accept(struct flow_info * flow,
buffer_t * symmkey,
buffer_t * data,
struct timespec * abstime)
{
- struct oap_hdr oap_hdr; /* incoming request */
- struct oap_hdr r_oap_hdr; /* outgoing response */
- uint8_t buf[MSGBUFSZ]; /* buffer for local ephkey */
- buffer_t lpk = BUF_INIT; /* local ephemeral pubkey */
- ssize_t delta; /* allocation time difference */
- int err;
- struct timespec now;
+ struct oap_hdr oap_hdr; /* incoming request */
+ struct oap_hdr r_oap_hdr; /* outgoing response */
+ uint8_t buf[MSGBUFSZ]; /* buffer for local ephkey */
+ buffer_t lpk = BUF_INIT; /* local ephemeral pubkey */
+ char name[NAME_SIZE + 1]; /* name for flow */
+ void * pkp = NULL; /* signing private key */
+ void * crt = NULL; /* signing certificate */
+ int err;
/* piggyback of user data not yet implemented */
- assert(data != NULL && data->len == 0 && data->data == NULL);
- assert(symmkey != NULL && symmkey->len == 0 && symmkey->data == NULL);
+ assert(data != NULL && BUF_IS_EMPTY(data));
+ assert(symmkey != NULL && BUF_IS_EMPTY(symmkey));
if (!reg_has_proc(flow->n_pid)) {
log_err("Unknown process %d calling accept.", flow->n_pid);
@@ -816,23 +1071,28 @@ static int flow_accept(struct flow_info * flow,
assert(err == 0);
- if (oap_hdr_decode(oap_hdr.hdr, &oap_hdr) < 0) {
- log_err("Failed to decode OAP header.");
+ if (reg_get_name_for_flow_id(name, flow->id) < 0) {
+ log_err("Failed to get name for flow %d.", flow->id);
err = -EIPCP;
goto fail_oap_hdr;
}
- clock_gettime(CLOCK_REALTIME, &now);
-
- delta = (ssize_t)(TS_TO_UINT64(now) - oap_hdr.timestamp) / MILLION;
- if (delta > flow->mpl)
- log_warn("Flow alloc time exceeds MPL (%zd ms).", delta);
+ log_dbg("IPCP %d accepting flow %d for %s.",
+ flow->n_pid, flow->id, name);
- if (delta < -TIMESYNC_SLACK)
- log_warn("Flow alloc sent from the future (%zd ms).", -delta);
+ if (oap_hdr_decode(oap_hdr.hdr, &oap_hdr) < 0) {
+ log_err("Failed to decode OAP header from %s.", name);
+ err = -EIPCP;
+ goto fail_oap_hdr;
+ }
#ifdef DEBUG_PROTO_OAP
debug_oap_hdr_rcv(&oap_hdr);
#endif
+ if (irm_check_oap_hdr(&oap_hdr, flow->mpl) < 0) {
+ log_err("OAP header failed replay check.");
+ goto fail_oap_hdr;
+ }
+
if (flow->qs.cypher_s != 0) { /* crypto requested */
uint8_t * s; /* symmetric encryption key */
ssize_t key_len; /* length of local pubkey */
@@ -872,25 +1132,47 @@ static int flow_accept(struct flow_info * flow,
crypt_dh_pkp_destroy(pkp);
}
- if (oap_hdr_init(oap_hdr.id, NULL, NULL, lpk, *data, &r_oap_hdr) < 0) {
+ if (load_srv_credentials(name, &pkp, &crt) < 0) {
+ log_err("Failed to load security keys for %s.", name);
+ err = -EAUTH;
+ goto fail_cred;
+ }
+
+ if (oap_hdr_init(oap_hdr.id, pkp, crt, lpk, *data, &r_oap_hdr) < 0) {
log_err("Failed to create OAP header.");
err = -ENOMEM;
goto fail_r_oap_hdr;
}
+
+ if (irm_auth_peer(name, &oap_hdr, &r_oap_hdr) < 0) {
+ log_err("Failed to authenticate %s flow %d.", name, flow->id);
+ err = -EAUTH;
+ goto fail_r_oap_hdr;
+ }
+
+ crypt_free_crt(crt);
+ crypt_free_key(pkp);
+
#ifdef DEBUG_PROTO_OAP
- debug_oap_hdr_snd(&oap_hdr);
+ debug_oap_hdr_snd(&r_oap_hdr);
#endif
if (ipcp_flow_alloc_resp(flow, 0, r_oap_hdr.hdr) < 0) {
log_err("Failed to respond to flow allocation.");
goto fail_resp;
}
+ log_info("Flow %d accepted by %d for %s.",
+ flow->id, flow->n_pid, name);
+
oap_hdr_fini(&oap_hdr);
oap_hdr_fini(&r_oap_hdr);
return 0;
fail_r_oap_hdr:
+ crypt_free_crt(crt);
+ crypt_free_key(pkp);
+ fail_cred:
freebuf(*symmkey);
fail_derive:
clrbuf(lpk);
@@ -949,7 +1231,6 @@ static int flow_join(struct flow_info * flow,
reg_prepare_flow_alloc(flow);
-
if (ipcp_flow_join(flow, hash)) {
log_err("Flow join with layer %s failed.", dst);
err = -ENOTALLOC;
@@ -1059,14 +1340,16 @@ static int flow_alloc(struct flow_info * flow,
buffer_t lpk = BUF_INIT; /* local ephemeral pubkey */
void * pkp = NULL; /* ephemeral private key pair */
uint8_t * s = NULL; /* symmetric key */
+ void * cpkp = NULL; /* signing private key */
+ void * ccrt = NULL; /* signing certificate */
buffer_t hash;
uint8_t idbuf[OAP_ID_SIZE];
buffer_t id;
int err;
/* piggyback of user data not yet implemented */
- assert(data != NULL && data->len == 0 && data->data == NULL);
- assert(symmkey != NULL && symmkey->len == 0 && symmkey->data == NULL);
+ assert(data != NULL && BUF_IS_EMPTY(data));
+ assert(symmkey != NULL && BUF_IS_EMPTY(symmkey));
if (random_buffer(idbuf, OAP_ID_SIZE) < 0) {
log_err("Failed to generate ID.");
@@ -1100,7 +1383,13 @@ static int flow_alloc(struct flow_info * flow,
log_dbg("Generated ephemeral keys for %d.", flow->n_pid);
}
- if (oap_hdr_init(id, NULL, NULL, lpk, *data, &oap_hdr) < 0) {
+ if (load_cli_credentials(dst, &cpkp, &ccrt) < 0) {
+ log_err("Failed to load security keys for %s.", dst);
+ err = -EAUTH;
+ goto fail_cred;
+ }
+
+ if (oap_hdr_init(id, cpkp, ccrt, lpk, *data, &oap_hdr) < 0) {
log_err("Failed to create OAP header.");
err = -ENOMEM;
goto fail_oap_hdr;
@@ -1164,9 +1453,14 @@ static int flow_alloc(struct flow_info * flow,
#ifdef DEBUG_PROTO_OAP
debug_oap_hdr_rcv(&r_oap_hdr);
#endif
- if (memcmp(r_oap_hdr.id.data, oap_hdr.id.data, r_oap_hdr.id.len) != 0) {
- log_err("OAP ID mismatch in flow allocation.");
- err = -EIPCP;
+ if (irm_check_oap_hdr(&r_oap_hdr, flow->mpl) < 0) {
+ log_err("OAP header failed replay check.");
+ goto fail_r_oap_hdr;
+ }
+
+ if (irm_auth_peer(dst, &oap_hdr, &r_oap_hdr) < 0) {
+ log_err("Failed to authenticate %s (flow %d).", dst, flow->id);
+ err = -EAUTH;
goto fail_r_oap_hdr;
}
@@ -1186,6 +1480,9 @@ static int flow_alloc(struct flow_info * flow,
oap_hdr_fini(&r_oap_hdr);
oap_hdr_fini(&oap_hdr);
+ crypt_free_crt(ccrt);
+ crypt_free_key(cpkp);
+
/* TODO: piggyback user data if needed */
freebuf(hash);
@@ -1203,6 +1500,9 @@ static int flow_alloc(struct flow_info * flow,
fail_flow:
oap_hdr_fini(&oap_hdr);
fail_oap_hdr:
+ crypt_free_crt(ccrt);
+ crypt_free_key(cpkp);
+ fail_cred:
crypt_dh_pkp_destroy(pkp);
fail_pkp:
free(s);
@@ -1497,8 +1797,7 @@ static irm_msg_t * do_command_msg(irm_msg_t * msg)
res = list_ipcps(&ret_msg->ipcps, &ret_msg->n_ipcps);
break;
case IRM_MSG_CODE__IRM_CREATE_NAME:
- strcpy(name.name, msg->names[0]->name);
- name.pol_lb = msg->names[0]->pol_lb;
+ name = name_info_msg_to_s(msg->name_info);
res = name_create(&name);
break;
case IRM_MSG_CODE__IRM_DESTROY_NAME:
@@ -1708,40 +2007,6 @@ static void * mainloop(void * o)
return (void *) 0;
}
-static void irm_fini(void)
-{
-#ifdef HAVE_FUSE
- struct timespec wait = TIMESPEC_INIT_MS(1);
- int retries = 5;
-#endif
- if (irmd_get_state() != IRMD_NULL)
- log_warn("Unsafe destroy.");
-
- tpm_destroy(irmd.tpm);
-
- close(irmd.sockfd);
-
- if (unlink(IRM_SOCK_PATH))
- log_dbg("Failed to unlink %s.", IRM_SOCK_PATH);
-
- if (irmd.rdrb != NULL)
- shm_rdrbuff_destroy(irmd.rdrb);
-
- if (irmd.lf != NULL)
- lockfile_destroy(irmd.lf);
-
- pthread_mutex_destroy(&irmd.cmd_lock);
- pthread_cond_destroy(&irmd.cmd_cond);
- pthread_rwlock_destroy(&irmd.state_lock);
-
-#ifdef HAVE_FUSE
- while (rmdir(FUSE_PREFIX) < 0 && retries-- > 0)
- nanosleep(&wait, NULL);
- if (retries < 0)
- log_err("Failed to remove " FUSE_PREFIX);
-#endif
-}
-
#ifdef HAVE_FUSE
static void destroy_mount(char * mnt)
{
@@ -1817,6 +2082,79 @@ void * irm_sanitize(void * o)
return (void *) 0;
}
+static int irm_load_store(char * dpath)
+{
+ struct stat st;
+ struct dirent * dent;
+ DIR * dir;
+ void * crt;
+
+ if (stat(dpath, &st) == -1) {
+ log_dbg("Store directory %s not found.", dpath);
+ return 0;
+ }
+
+ if (!S_ISDIR(st.st_mode)) {
+ log_err("%s is not a directory.", dpath);
+ goto fail_dir;
+ }
+
+ /* loop through files in directory and load certificates */
+ dir = opendir(dpath);
+ if (dir == NULL) {
+ log_err("Failed to open %s.", dpath);
+ goto fail_dir;
+ }
+
+ while ((dent = readdir(dir)) != NULL) {
+ char path[NAME_PATH_SIZE + 1];
+
+ if (strcmp(dent->d_name, ".") == 0 ||
+ strcmp(dent->d_name, "..") == 0)
+ continue;
+
+ snprintf(path, sizeof(path), "%s/%s", dpath,
+ dent->d_name);
+
+ if (stat(path, &st) == -1) {
+ log_dbg("Failed to stat %s.", path);
+ continue;
+ }
+
+ if (!S_ISREG(st.st_mode)) {
+ log_dbg("%s is not a regular file.", path);
+ goto fail_file;
+ }
+
+ if (crypt_load_crt_file(path, &crt) < 0) {
+ log_err("Failed to load certificate from %s.", path);
+ goto fail_file;
+ }
+
+ if (auth_add_crt_to_store(irmd.auth.ctx, crt) < 0) {
+ log_err("Failed to add certificate from %s to store.",
+ path);
+ goto fail_crt_add;
+ }
+
+ log_dbg("Loaded certificate: %s.", path);
+
+ crypt_free_crt(crt);
+ }
+
+ closedir(dir);
+
+ log_info("Loaded certificates from %s.", dpath);
+
+ return 0;
+
+ fail_crt_add:
+ crypt_free_crt(crt);
+ fail_file:
+ closedir(dir);
+ fail_dir:
+ return -1;
+}
static int irm_init(void)
{
@@ -1917,6 +2255,30 @@ static int irm_init(void)
log_err("Failed to greate thread pool.");
goto fail_tpm_create;
}
+
+ if (pthread_mutex_init(&irmd.auth.mtx, NULL) < 0) {
+ log_err("Failed to initialize auth mutex.");
+ goto fail_auth_mtx;
+ }
+
+ irmd.auth.ctx = auth_create_ctx();
+ if (irmd.auth.ctx == NULL) {
+ log_err("Failed to create auth store context.");
+ goto fail_auth_ctx;
+ }
+
+ list_head_init(&irmd.auth.list);
+
+ if (irm_load_store(OUROBOROS_CA_CRT_DIR) < 0) {
+ log_err("Failed to load CA certificates.");
+ goto fail_auth_ctx;
+ }
+
+ if (irm_load_store(OUROBOROS_CHAIN_DIR) < 0) {
+ log_err("Failed to load intermediate certificates.");
+ goto fail_auth_ctx;
+ }
+
#ifdef HAVE_FUSE
mask = umask(0);
@@ -1941,7 +2303,6 @@ static int irm_init(void)
gcry_control(GCRYCTL_INITIALIZATION_FINISHED);
#endif
-
return 0;
#ifdef HAVE_LIBGCRYPT
@@ -1949,8 +2310,12 @@ static int irm_init(void)
#ifdef HAVE_FUSE
rmdir(FUSE_PREFIX);
#endif
- tpm_destroy(irmd.tpm);
+ auth_destroy_ctx(irmd.auth.ctx);
#endif
+ fail_auth_ctx:
+ pthread_mutex_destroy(&irmd.auth.mtx);
+ fail_auth_mtx:
+ tpm_destroy(irmd.tpm);
fail_tpm_create:
shm_rdrbuff_destroy(irmd.rdrb);
fail_rdrbuff:
@@ -1970,6 +2335,67 @@ static int irm_init(void)
return -1;
}
+static void irm_fini(void)
+{
+ struct list_head * p;
+ struct list_head * h;
+#ifdef HAVE_FUSE
+ struct timespec wait = TIMESPEC_INIT_MS(1);
+ int retries = 5;
+#endif
+ if (irmd_get_state() != IRMD_NULL)
+ log_warn("Unsafe destroy.");
+
+ pthread_mutex_lock(&irmd.auth.mtx);
+
+ list_for_each_safe(p, h, &irmd.auth.list) {
+ struct oaph * oaph = list_entry(p, struct oaph, next);
+ list_del(&oaph->next);
+ free(oaph);
+ }
+
+ pthread_mutex_unlock(&irmd.auth.mtx);
+ pthread_mutex_destroy(&irmd.auth.mtx);
+
+ auth_destroy_ctx(irmd.auth.ctx);
+
+ tpm_destroy(irmd.tpm);
+
+ close(irmd.sockfd);
+
+ if (unlink(IRM_SOCK_PATH))
+ log_dbg("Failed to unlink %s.", IRM_SOCK_PATH);
+
+ if (irmd.rdrb != NULL)
+ shm_rdrbuff_destroy(irmd.rdrb);
+
+ if (irmd.lf != NULL)
+ lockfile_destroy(irmd.lf);
+
+ pthread_mutex_lock(&irmd.cmd_lock);
+
+ list_for_each_safe(p, h, &irmd.cmds) {
+ struct cmd * cmd = list_entry(p, struct cmd, next);
+ list_del(&cmd->next);
+ close(cmd->fd);
+ free(cmd);
+ }
+
+ pthread_mutex_unlock(&irmd.cmd_lock);
+
+ pthread_mutex_destroy(&irmd.cmd_lock);
+ pthread_cond_destroy(&irmd.cmd_cond);
+ pthread_rwlock_destroy(&irmd.state_lock);
+
+#ifdef HAVE_FUSE
+ while (rmdir(FUSE_PREFIX) < 0 && retries-- > 0)
+ nanosleep(&wait, NULL);
+ if (retries < 0)
+ log_err("Failed to remove " FUSE_PREFIX);
+#endif
+ assert(list_is_empty(&irmd.cmds));
+}
+
static void usage(void)
{
printf("Usage: irmd \n"
@@ -2096,8 +2522,8 @@ static void * kill_dash_nine(void * o)
slept += intv;
}
- log_dbg("I am become Death, destroyer of hung processes.");
-
+ log_dbg("I guess I’ll have to shut you down for good this time,");
+ log_dbg("already tried a SIGQUIT, so now it’s KILL DASH 9.");
#ifdef IRMD_KILL_ALL_PROCESSES
reg_kill_all_proc(SIGKILL);
nanosleep(&ts, NULL);
@@ -2156,7 +2582,7 @@ int main(int argc,
if (geteuid() != 0) {
printf("IPC Resource Manager must be run as root.\n");
- exit(EXIT_FAILURE);
+ goto fail_irm_init;
}
if (irm_init() < 0)
diff --git a/src/irmd/reg/flow.h b/src/irmd/reg/flow.h
index b0f0c51c..aba0d7a4 100644
--- a/src/irmd/reg/flow.h
+++ b/src/irmd/reg/flow.h
@@ -25,6 +25,7 @@
#include <ouroboros/list.h>
#include <ouroboros/flow.h>
+#include <ouroboros/name.h>
#include <ouroboros/pthread.h>
#include <ouroboros/qos.h>
#include <ouroboros/shm_rbuff.h>
@@ -41,6 +42,8 @@ struct reg_flow {
buffer_t data;
struct timespec t0;
+ char name[NAME_SIZE + 1];
+
struct shm_rbuff * n_rb;
struct shm_rbuff * n_1_rb;
};
diff --git a/src/irmd/reg/name.c b/src/irmd/reg/name.c
index 1ac939a5..4e609711 100644
--- a/src/irmd/reg/name.c
+++ b/src/irmd/reg/name.c
@@ -66,15 +66,14 @@ struct reg_name * reg_name_create(const struct name_info * info)
goto fail_malloc;
}
+ memset(name, 0, sizeof(*name));
+
list_head_init(&name->next);
- list_head_init(&name->progs);
- list_head_init(&name->procs);
- list_head_init(&name->active);
+ list_head_init(&name->progs.list);
+ list_head_init(&name->procs.list);
+ list_head_init(&name->active.list);
- name->info = *info;
- name->n_progs = 0;
- name->n_procs = 0;
- name->n_active = 0;
+ name->info = *info;
return name;
@@ -88,13 +87,13 @@ void reg_name_destroy(struct reg_name * name)
assert(list_is_empty(&name->next));
- assert(name->n_progs == 0);
- assert(name->n_procs == 0);
- assert(name->n_active == 0);
+ assert(name->progs.len == 0);
+ assert(name->procs.len == 0);
+ assert(name->active.len == 0);
- assert(list_is_empty(&name->progs));
- assert(list_is_empty(&name->procs));
- assert(list_is_empty(&name->active));
+ assert(list_is_empty(&name->progs.list));
+ assert(list_is_empty(&name->procs.list));
+ assert(list_is_empty(&name->active.list));
free(name);
}
@@ -107,7 +106,7 @@ static struct proc_entry * __reg_name_get_active(const struct reg_name * name,
assert(name != NULL);
assert(pid > 0);
- list_for_each(p, &name->active) {
+ list_for_each(p, &name->active.list) {
struct proc_entry * entry;
entry = list_entry(p, struct proc_entry, next);
if (entry->pid == pid)
@@ -123,13 +122,13 @@ static void __reg_name_del_all_active(struct reg_name * name,
struct list_head * p;
struct list_head * h;
- list_for_each_safe(p, h, &name->active) {
+ list_for_each_safe(p, h, &name->active.list) {
struct proc_entry * entry;
entry = list_entry(p, struct proc_entry, next);
if (entry->pid == pid) {
list_del(&entry->next);
free(entry);
- name->n_active--;
+ --name->active.len;
}
}
}
@@ -142,7 +141,7 @@ static struct proc_entry * __reg_name_get_proc(const struct reg_name * name,
assert(name != NULL);
assert(pid > 0);
- list_for_each(p, &name->procs) {
+ list_for_each(p, &name->procs.list) {
struct proc_entry * entry;
entry = list_entry(p, struct proc_entry, next);
if (entry->pid == pid)
@@ -160,7 +159,7 @@ static struct prog_entry * __reg_name_get_prog(const struct reg_name * name,
assert(name != NULL);
assert(prog != NULL);
- list_for_each(p, &name->progs) {
+ list_for_each(p, &name->progs.list) {
struct prog_entry * entry;
entry = list_entry(p, struct prog_entry, next);
if (strcmp(entry->exec[0], prog) == 0)
@@ -195,16 +194,16 @@ int reg_name_add_active(struct reg_name * name,
switch (name->info.pol_lb) {
case LB_RR: /* Round robin policy. */
- list_add_tail(&entry->next, &name->active);
+ list_add_tail(&entry->next, &name->active.list);
break;
case LB_SPILL: /* Keep accepting flows on the current process */
- list_add(&entry->next, &name->active);
+ list_add(&entry->next, &name->active.list);
break;
default:
goto fail_unreachable;
}
- name->n_active++;
+ ++name->active.len;
return 0;
@@ -226,19 +225,23 @@ void reg_name_del_active(struct reg_name * name,
list_del(&entry->next);
- name->n_active--;
+ --name->active.len;
free(entry);
}
pid_t reg_name_get_active(struct reg_name * name)
{
+ struct proc_entry * e;
+
assert(name != NULL);
- if (list_is_empty(&name->active))
+ if (list_is_empty(&name->active.list))
return -1;
- return list_first_entry(&name->active, struct proc_entry, next)->pid;
+ e = list_first_entry(&name->active.list, struct proc_entry, next);
+
+ return e->pid;
}
int reg_name_add_proc(struct reg_name * name,
@@ -259,9 +262,9 @@ int reg_name_add_proc(struct reg_name * name,
entry->pid = pid;
- list_add(&entry->next, &name->procs);
+ list_add(&entry->next, &name->procs.list);
- name->n_procs++;
+ ++name->procs.len;
return 0;
@@ -287,7 +290,7 @@ void reg_name_del_proc(struct reg_name * name,
free(entry);
- name->n_procs--;
+ --name->procs.len;
assert(__reg_name_get_proc(name, pid) == NULL);
}
@@ -296,8 +299,7 @@ bool reg_name_has_proc(const struct reg_name * name,
pid_t pid)
{
return __reg_name_get_proc(name, pid) != NULL;
-} char ** exec;
-
+}
int reg_name_add_prog(struct reg_name * name,
char ** exec)
@@ -322,11 +324,11 @@ int reg_name_add_prog(struct reg_name * name,
goto fail_exec;
}
- list_add(&entry->next, &name->progs);
+ list_add(&entry->next, &name->progs.list);
log_dbg("Add prog %s to name %s.", exec[0], name->info.name);
- name->n_progs++;
+ ++name->progs.len;
return 0;
@@ -352,7 +354,7 @@ void reg_name_del_prog(struct reg_name * name,
__free_prog_entry(entry);
- name->n_progs--;
+ --name->progs.len;
assert(__reg_name_get_prog(name, prog) == NULL);
}
@@ -368,8 +370,12 @@ bool reg_name_has_prog(const struct reg_name * name,
char ** reg_name_get_exec(const struct reg_name * name)
{
- if (list_is_empty(&name->progs))
+ struct prog_entry * e;
+
+ if (list_is_empty(&name->progs.list))
return NULL;
- return list_first_entry(&name->progs, struct prog_entry, next)->exec;
+ e = list_first_entry(&name->progs.list, struct prog_entry, next);
+
+ return e->exec;
}
diff --git a/src/irmd/reg/name.h b/src/irmd/reg/name.h
index 97ca7f04..30a64e1c 100644
--- a/src/irmd/reg/name.h
+++ b/src/irmd/reg/name.h
@@ -33,14 +33,25 @@ struct reg_name {
struct name_info info;
- struct list_head progs; /* autostart programs for this name */
- size_t n_progs; /* number of programs */
-
- struct list_head procs; /* processes bound to this name */
- size_t n_procs; /* number of processes */
-
- struct list_head active; /* processes actively calling accept */
- size_t n_active; /* number of processes accepting */
+ struct {
+ void * key;
+ void * crt;
+ } cache;
+
+ struct {
+ struct list_head list;
+ size_t len;
+ } progs; /* autostart programs for this name */
+
+ struct {
+ struct list_head list;
+ size_t len;
+ } procs; /* processes bound to this name */
+
+ struct {
+ struct list_head list;
+ size_t len;
+ } active; /* processes actively calling accept */
};
struct reg_name * reg_name_create(const struct name_info * info);
@@ -74,5 +85,4 @@ pid_t reg_name_get_active(struct reg_name * name);
void reg_name_del_active(struct reg_name * name,
pid_t proc);
-
#endif /* OUROBOROS_IRMD_REG_NAME_H */
diff --git a/src/irmd/reg/reg.c b/src/irmd/reg/reg.c
index 8d1fa8cf..0d4c6f24 100644
--- a/src/irmd/reg/reg.c
+++ b/src/irmd/reg/reg.c
@@ -28,6 +28,7 @@ The IPC Resource Manager - Registry
#include <ouroboros/errno.h>
#include <ouroboros/list.h>
#include <ouroboros/logs.h>
+#include <ouroboros/protobuf.h>
#include <ouroboros/pthread.h>
#include "reg.h"
@@ -46,6 +47,7 @@ The IPC Resource Manager - Registry
struct {
struct bmp * flow_ids; /* flow_ids for flows */
+
struct list_head flows; /* flow information */
size_t n_flows; /* number of flows */
@@ -196,6 +198,10 @@ static int __reg_get_pending_flow_id(const char * name)
struct reg_flow * flow;
pid_t pid;
+ assert(name != NULL);
+ assert(strlen(name) > 0);
+ assert(strlen(name) < NAME_SIZE + 1);
+
entry =__reg_get_name(name);
if (entry == NULL)
return -ENAME;
@@ -205,7 +211,10 @@ static int __reg_get_pending_flow_id(const char * name)
return -EAGAIN;
flow = __reg_get_accept_flow(pid);
- assert(flow != NULL);
+ if (flow == NULL) /* compiler barks, this can't be NULL */
+ return -EAGAIN;
+
+ strcpy(flow->name, name);
return flow->info.id;
}
@@ -580,6 +589,14 @@ void reg_clear(void)
reg.n_procs--;
}
+ list_for_each_safe(p, h, &reg.flows) {
+ struct reg_flow * entry;
+ entry = list_entry(p, struct reg_flow, next);
+ list_del(&entry->next);
+ reg_flow_destroy(entry);
+ reg.n_flows--;
+ }
+
list_for_each_safe(p, h, &reg.names) {
struct reg_name * entry;
entry = list_entry(p, struct reg_name, next);
@@ -596,14 +613,6 @@ void reg_clear(void)
reg.n_ipcps--;
}
- list_for_each_safe(p, h, &reg.flows) {
- struct reg_flow * entry;
- entry = list_entry(p, struct reg_flow, next);
- list_del(&entry->next);
- reg_flow_destroy(entry);
- reg.n_flows--;
- }
-
pthread_mutex_unlock(&reg.mtx);
}
@@ -950,6 +959,34 @@ bool reg_has_name(const char * name)
return ret;
}
+int reg_get_name_info(const char * name,
+ struct name_info * info)
+{
+ struct reg_name * n;
+
+ assert(name != NULL);
+ assert(info != NULL);
+
+ pthread_mutex_lock(&reg.mtx);
+
+ n = __reg_get_name(name);
+ if (n == NULL) {
+ log_err("Name %s does not exist.", name);
+ goto no_name;
+ }
+
+ *info = n->info;
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return 0;
+
+ no_name:
+ pthread_mutex_unlock(&reg.mtx);
+ return -ENOENT;
+
+}
+
int reg_get_name_for_hash(char * buf,
enum hash_algo algo,
const uint8_t * hash)
@@ -986,29 +1023,20 @@ int reg_get_name_for_hash(char * buf,
return name == NULL ? -ENOENT : 0;
}
-
-static int __get_name_info(name_info_msg_t ** msg,
- struct reg_name * n)
+int reg_get_name_for_flow_id(char * buf,
+ int flow_id)
{
- *msg = malloc(sizeof(**msg));
- if (*msg == NULL)
- goto fail;
-
- name_info_msg__init(*msg);
+ struct reg_flow * f;
- (*msg)->name = strdup(n->info.name);
- if ((*msg)->name == NULL)
- goto fail_msg;
+ pthread_mutex_lock(&reg.mtx);
- (*msg)->pol_lb = n->info.pol_lb;
+ f = __reg_get_flow(flow_id);
+ if (f != NULL)
+ strcpy(buf, f->name);
- return 0;
+ pthread_mutex_unlock(&reg.mtx);
- fail_msg:
- name_info_msg__free_unpacked(*msg, NULL);
- *msg = NULL;
- fail:
- return -1;
+ return f == NULL ? -ENOENT : 0;
}
int reg_list_names(name_info_msg_t *** names)
@@ -1030,10 +1058,20 @@ int reg_list_names(name_info_msg_t *** names)
list_for_each(p, &reg.names) {
struct reg_name * entry;
entry = list_entry(p, struct reg_name, next);
- if (__get_name_info(&(*names)[i], entry) < 0) {
+ (*names)[i] = name_info_s_to_msg(&entry->info);
+ if ((*names)[i] == NULL) {
log_err("Failed to create name list info.");
goto fail;
}
+ /* wipe security info to avoid huge messages */
+ free((*names)[i]->scrt);
+ (*names)[i]->scrt = NULL;
+ free((*names)[i]->skey);
+ (*names)[i]->skey = NULL;
+ free((*names)[i]->ccrt);
+ (*names)[i]->ccrt = NULL;
+ free((*names)[i]->ckey);
+ (*names)[i]->ckey = NULL;
i++;
}
@@ -1947,12 +1985,14 @@ void reg_dealloc_flow(struct flow_info * info)
assert(flow != NULL);
assert(flow->data.data == NULL);
assert(flow->data.len == 0);
-
assert(flow->info.state == FLOW_ALLOCATED);
+
flow->info.state = FLOW_DEALLOC_PENDING;
info->state = FLOW_DEALLOC_PENDING;
info->n_1_pid = flow->info.n_1_pid;
+ memset(flow->name, 0, sizeof(flow->name));
+
reg_flow_update(flow, info);
pthread_mutex_unlock(&reg.mtx);
diff --git a/src/irmd/reg/reg.h b/src/irmd/reg/reg.h
index 00db8f0b..57257dd5 100644
--- a/src/irmd/reg/reg.h
+++ b/src/irmd/reg/reg.h
@@ -90,10 +90,16 @@ int reg_destroy_name(const char * name);
bool reg_has_name(const char * name);
+int reg_get_name_info(const char * name,
+ struct name_info * info);
+
int reg_get_name_for_hash(char * buf,
enum hash_algo algo,
const uint8_t * hash);
+int reg_get_name_for_flow_id(char * buf,
+ int flow_id);
+
/* TODO don't rely on protobuf here */
int reg_list_names(name_info_msg_t *** names);
diff --git a/src/irmd/reg/tests/name_test.c b/src/irmd/reg/tests/name_test.c
index 64635eec..9071364b 100644
--- a/src/irmd/reg/tests/name_test.c
+++ b/src/irmd/reg/tests/name_test.c
@@ -76,8 +76,8 @@ static int test_reg_name_add_proc(void)
goto fail;
}
- if (n->n_procs != 1) {
- printf("n_procs not updated.\n");
+ if (n->procs.len != 1) {
+ printf("Proc not added to list.\n");
goto fail;
}
@@ -88,8 +88,8 @@ static int test_reg_name_add_proc(void)
reg_name_del_proc(n, TEST_PID);
- if (n->n_procs != 0) {
- printf("n_procs not updated.\n");
+ if (n->procs.len != 0) {
+ printf("Proc not removed from list.\n");
goto fail;
}
@@ -126,8 +126,8 @@ static int test_reg_name_add_prog(void)
goto fail;
}
- if (n->n_progs != 1) {
- printf("n_progs not updated.\n");
+ if (n->progs.len != 1) {
+ printf("Prog not added to list.\n");
goto fail;
}
@@ -138,8 +138,8 @@ static int test_reg_name_add_prog(void)
reg_name_del_prog(n, TEST_PROG);
- if (n->n_progs != 0) {
- printf("n_progs not updated.\n");
+ if (n->progs.len != 0) {
+ printf("Prog not removed from list.\n");
goto fail;
}
@@ -195,8 +195,8 @@ static int test_reg_name_add_active(enum pol_balance lb)
goto fail;
}
- if (n->n_active != 1) {
- printf("n_active not updated.\n");
+ if (n->active.len != 1) {
+ printf("Active list not updated.\n");
goto fail;
}
@@ -226,13 +226,13 @@ static int test_reg_name_add_active(enum pol_balance lb)
goto fail;
}
- if (n->n_procs != 3) {
- printf("n_procs not updated.\n");
+ if (n->procs.len != 3) {
+ printf("Procs list not updated.\n");
goto fail;
}
- if (n->n_active != 4) {
- printf("n_active not updated.\n");
+ if (n->active.len != 4) {
+ printf("Active list not updated.\n");
goto fail;
}
@@ -263,13 +263,13 @@ static int test_reg_name_add_active(enum pol_balance lb)
reg_name_del_proc(n, TEST_PID);
- if (n->n_procs != 0) {
- printf("n_procs not updated.\n");
+ if (n->procs.len != 0) {
+ printf("Procs list not cleared.\n");
goto fail;
}
- if (n->n_active != 0) {
- printf("n_active not updated.\n");
+ if (n->active.len != 0) {
+ printf("Active list not cleared.\n");
goto fail;
}
@@ -283,20 +283,19 @@ static int test_reg_name_add_active(enum pol_balance lb)
return TEST_RC_FAIL;
}
-
int name_test(int argc,
char ** argv)
{
- int res = 0;
+ int rc = 0;
(void) argc;
(void) argv;
- res |= test_reg_name_create();
- res |= test_reg_name_add_proc();
- res |= test_reg_name_add_prog();
- res |= test_reg_name_add_active(LB_RR);
- res |= test_reg_name_add_active(LB_SPILL);
+ rc |= test_reg_name_create();
+ rc |= test_reg_name_add_proc();
+ rc |= test_reg_name_add_prog();
+ rc |= test_reg_name_add_active(LB_RR);
+ rc |= test_reg_name_add_active(LB_SPILL);
- return res;
+ return rc;
}
diff --git a/src/irmd/reg/tests/reg_test.c b/src/irmd/reg/tests/reg_test.c
index fb99e6d3..280ea9a8 100644
--- a/src/irmd/reg/tests/reg_test.c
+++ b/src/irmd/reg/tests/reg_test.c
@@ -36,7 +36,7 @@
#define TEST_DATA2 "testpbufdata2"
#define TEST_LAYER "testlayer"
#define REG_TEST_FAIL() \
- do { TEST_FAIL(); memset(&reg, 0, sizeof(reg)); } while(0)
+ do { TEST_FAIL(); memset(&reg, 0, sizeof(reg)); abort();} while(0)
static int test_reg_init(void)
{
@@ -254,7 +254,7 @@ static int test_reg_accept_flow_success(void)
pthread_create(&thr, NULL, test_flow_respond_accept, &n_1_info);
- if (reg_wait_flow_accepted(&info, &rbuf, &abstime) < 0 ) {
+ if (reg_wait_flow_accepted(&info, &rbuf, &abstime) < 0) {
printf("Flow allocation failed.\n");
goto fail;
}
@@ -1344,13 +1344,14 @@ static int test_wait_accepting_success(void)
{
struct timespec abstime;
struct timespec timeo = TIMESPEC_INIT_S(1);
- int flow_id;
pthread_t thr;
+ int flow_id;
struct name_info ninfo = {
.name = TEST_NAME,
.pol_lb = LB_RR
};
+
TEST_START();
if (reg_init()) {
diff --git a/src/irmd/tests/oap_test.c b/src/irmd/tests/oap_test.c
index 2e27762d..4e7fb2d1 100644
--- a/src/irmd/tests/oap_test.c
+++ b/src/irmd/tests/oap_test.c
@@ -210,6 +210,16 @@ static int test_oap_hdr_init_fini_signed(void)
goto fail_req_hdr;
}
+ if (oap_hdr.crt.len == 0) {
+ printf("OAP request header has no public certificate.\n");
+ goto fail_req_hdr;
+ }
+
+ if (oap_hdr.sig.len == 0) {
+ printf("OAP request header no signature.\n");
+ goto fail_req_hdr;
+ }
+
if (crypt_load_crt_der(oap_hdr.crt, &pubcrt2) < 0) {
printf("Failed to load public certificate from DER.\n");
goto fail_crt_der;