diff options
author | Dimitri Staessens <dimitri@ouroboros.rocks> | 2025-08-13 09:03:20 +0200 |
---|---|---|
committer | Dimitri Staessens <dimitri@ouroboros.rocks> | 2025-08-18 20:57:23 +0200 |
commit | e35302ca0ab64edd21b9d8e40d3aa74a3a4f4f7e (patch) | |
tree | 348711a66a585f982b19979f083e601fc85ed605 /src/irmd | |
parent | f1fcec220c8454cb461bd1ac22621a1b64609051 (diff) | |
download | ouroboros-e35302ca0ab64edd21b9d8e40d3aa74a3a4f4f7e.tar.gz ouroboros-e35302ca0ab64edd21b9d8e40d3aa74a3a4f4f7e.zip |
irmd: Add flow authentication
This adds initial implementation of peer authentication as part of
flow allocation. If credentials are not provided, this will be
accepted and logged as info that the flow is not authenticated.
Certificates and keys are passed as .pem files. The key file should
not be encrypted, else the IRMd will open a prompt for the password.
The default location for these .pem files is in
/etc/ouroboros/security. It is strongly recommended to make this
directory only accessible to root.
├── security
│ ├── cacert
│ │ └── ca.root.o7s.crt.pem
│ ├── client
│ │ ├── <name>
│ │ | ├── crt.pem
│ │ | └── key.pem
│ │ └── <name>
| | ├──...
| |
│ ├── server
│ │ ├── <name>
│ │ | ├── crt.pem
│ │ | └── key.pem
│ │ └── <name>
| | ├── ...
| |
│ └── untrusted
│ └── sign.root.o7s.crt.pem
Trusted root CA certificates go in the /cacert directory, untrusted
certificates for signature verification go in the /untrusted
directory. The IRMd will load these certificates at boot. The IRMd
will look for certificates in the /client and /server directories. For
each name a subdirectory can be added and the credentials in that
directory are used to sign the OAP header for flows at flow_alloc() on
the client side and flow_accept() on the server side.
These defaults can be changed at build time using the following
variables (in alphabetical order):
OUROBOROS_CA_CRT_DIR /etc/ouroboros/security/cacert
OUROBOROS_CLI_CRT_DIR /etc/ouroboros/security/client
OUROBOROS_SECURITY_DIR /etc/ouroboros/security
OUROBOROS_SRV_CRT_DIR /etc/ouroboros/security/server
OUROBOROS_UNTRUSTED_DIR /etc/ouroboros/security/untrusted
The directories for the names can also be configured at IRMd boot
using the configuraton file and at runtime when a name is created
using the "irm name create" CLI tool. The user needs to have
permissions to access the keyfile and certificate when specifying the
paths with the "irm name create" CLI tool.
Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks>
Diffstat (limited to 'src/irmd')
-rw-r--r-- | src/irmd/CMakeLists.txt | 18 | ||||
-rw-r--r-- | src/irmd/config.h.in | 7 | ||||
-rw-r--r-- | src/irmd/configfile.c | 115 | ||||
-rw-r--r-- | src/irmd/irmd.h | 2 | ||||
-rw-r--r-- | src/irmd/main.c | 648 | ||||
-rw-r--r-- | src/irmd/reg/flow.h | 3 | ||||
-rw-r--r-- | src/irmd/reg/name.c | 74 | ||||
-rw-r--r-- | src/irmd/reg/name.h | 28 | ||||
-rw-r--r-- | src/irmd/reg/reg.c | 98 | ||||
-rw-r--r-- | src/irmd/reg/reg.h | 6 | ||||
-rw-r--r-- | src/irmd/reg/tests/name_test.c | 51 | ||||
-rw-r--r-- | src/irmd/reg/tests/reg_test.c | 7 | ||||
-rw-r--r-- | src/irmd/tests/oap_test.c | 10 |
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, ®.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, ®.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, ®.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(®.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(®.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(®.mtx); + + return 0; + + no_name: + pthread_mutex_unlock(®.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(®.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(®.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, ®.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(®.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(®, 0, sizeof(reg)); } while(0) + do { TEST_FAIL(); memset(®, 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; |