summaryrefslogtreecommitdiff
path: root/ecp/server/acl.c
diff options
context:
space:
mode:
Diffstat (limited to 'ecp/server/acl.c')
-rw-r--r--ecp/server/acl.c275
1 files changed, 275 insertions, 0 deletions
diff --git a/ecp/server/acl.c b/ecp/server/acl.c
new file mode 100644
index 0000000..d8cdc6e
--- /dev/null
+++ b/ecp/server/acl.c
@@ -0,0 +1,275 @@
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include <ecp/core.h>
+#include <ecp/cr.h>
+#include <ecp/ht.h>
+#include <ecp/dir/dir.h>
+
+#include <util.h>
+
+#include "server.h"
+#include "acl.h"
+
+static SRVConfig *srv_config;
+
+static ecp_ht_table_t *acl_keys = NULL;
+static ecp_ht_table_t *acl_keys_dir = NULL;
+static pthread_mutex_t acl_li_mutex;
+static pthread_rwlock_t acl_ht_rwlock;
+static ACLItem *acl_head = NULL;
+static ACLItem *acl_head_dir = NULL;
+static int acl_mark = 0;
+
+ACLItem *acl_create_item(void) {
+ ACLItem *ret = NULL;
+
+ ret = malloc(sizeof(ACLItem));
+ if (ret == NULL) return ret;
+ memset(&ret->key, 0, sizeof(ret->key));
+ ret->key_cnt = 0;
+ ret->next = NULL;
+
+ return ret;
+}
+
+void acl_destroy_item(ACLItem *item) {
+ free(item);
+}
+
+void acl_destroy_list(ACLItem *head) {
+ ACLItem *acl_next;
+
+ while (head) {
+ acl_next = head->next;
+ acl_destroy_item(head);
+ head = acl_next;
+ }
+}
+
+static int _add_key(ecp_ecdh_public_t *public, uint8_t capabilities) {
+ int rv;
+
+ if ((acl_keys == NULL) || (acl_keys_dir == NULL)) return ECP_ERR;
+
+ if ((srv_config->capabilities & ECP_DIR_CAP_DIR) || (srv_config->capabilities & capabilities & ECP_DIR_CAP_VCONN)) {
+ /* directory server accepts all connections
+ vconn server accepts connections only from other vconn servers */
+ rv = ecp_ht_insert_uniq(acl_keys, public, &acl_mark);
+ if (rv && (rv != ECP_ERR_DUP)) return rv;
+ }
+ if (srv_config->capabilities & capabilities & ECP_DIR_CAP_DIR) {
+ rv = ecp_ht_insert_uniq(acl_keys_dir, public, &acl_mark);
+ if (rv && (rv != ECP_ERR_DUP)) return rv;
+ }
+
+ return ECP_OK;
+}
+
+static int _read_file(int fd, ACLItem *head) {
+ ecp_ecdh_public_t public;
+ int rv;
+
+ if (head == NULL) return ECP_ERR_ALLOC;
+
+ while (head->next) {
+ head = head->next;
+ }
+
+ while(ecp_util_read_key(fd, &public, NULL) == ECP_OK) {
+ if (head->key_cnt == ACL_MAX_KEY) {
+ head->next = acl_create_item();
+ if (head->next == NULL) return ECP_ERR_ALLOC;
+ head = head->next;
+ }
+ memcpy(&head->key[head->key_cnt], &public, sizeof(head->key[head->key_cnt]));
+ head->key_cnt++;
+ }
+
+ return ECP_OK;
+}
+
+static int _li2ht(ACLItem *head, int is_dir) {
+ int i;
+ int rv;
+
+ while (head) {
+ for (i=0; i<head->key_cnt; i++) {
+ rv = _add_key(&head->key[i], is_dir ? ECP_DIR_CAP_DIR : 0);
+ if (rv) return rv;
+ }
+ head = head->next;
+ }
+
+ return ECP_OK;
+}
+
+int acl_add_key(ECPDirItem *dir_item) {
+ int rv;
+
+ pthread_rwlock_wrlock(&acl_ht_rwlock);
+ rv = _add_key(&dir_item->node.key_perma.public, dir_item->capabilities);
+ pthread_rwlock_unlock(&acl_ht_rwlock);
+
+ return rv;
+}
+
+int acl_inlist(ecp_ecdh_public_t *public) {
+ void *item = NULL;
+
+ pthread_rwlock_rdlock(&acl_ht_rwlock);
+ if (acl_keys) item = ecp_ht_search(acl_keys, public);
+ pthread_rwlock_unlock(&acl_ht_rwlock);
+
+ return (item != NULL);
+}
+
+int acl_dir_inlist(ecp_ecdh_public_t *public) {
+ void *item = NULL;
+
+ pthread_rwlock_rdlock(&acl_ht_rwlock);
+ if (acl_keys_dir) item = ecp_ht_search(acl_keys_dir, public);
+ pthread_rwlock_unlock(&acl_ht_rwlock);
+
+ return (item != NULL);
+}
+
+int acl_reset_ht(void) {
+ int rv = ECP_OK;
+
+ pthread_rwlock_wrlock(&acl_ht_rwlock);
+ if (acl_keys) ecp_ht_destroy(acl_keys);
+ if (acl_keys_dir) ecp_ht_destroy(acl_keys_dir);
+ acl_keys = ecp_ht_create_keys();
+ acl_keys_dir = ecp_ht_create_keys();
+ if ((acl_keys == NULL) || (acl_keys_dir == NULL)) rv = ECP_ERR_ALLOC;
+ pthread_rwlock_unlock(&acl_ht_rwlock);
+
+ return rv;
+}
+
+int acl_load_ht(void) {
+ int rv = ECP_OK;
+ int _rv;
+
+ pthread_mutex_lock(&acl_li_mutex);
+ pthread_rwlock_wrlock(&acl_ht_rwlock);
+
+ _rv = _li2ht(acl_head, 0);
+ if (_rv) rv = ECP_ERR;
+ _rv = _li2ht(acl_head_dir, 1);
+ if (_rv) rv = ECP_ERR;
+
+ pthread_rwlock_unlock(&acl_ht_rwlock);
+ pthread_mutex_unlock(&acl_li_mutex);
+
+ return rv;
+}
+
+int acl_load(void) {
+ ACLItem *acl_new = NULL;
+ ACLItem *acl_dir_new = NULL;
+ int fd = -1;
+ int fd_dir = -1;
+ int rv = ECP_OK;
+ int _rv;
+
+ if ((srv_config->acl_fn == NULL) && (srv_config->acl_fn_dir == NULL)) return ECP_OK;
+
+ if (srv_config->acl_fn) {
+ fd = open(srv_config->acl_fn, O_RDONLY);
+ if (fd < 0) {
+ LOG(LOG_ERR, "acl_load: unable to open: %s\n", srv_config->acl_fn);
+ return ECP_ERR;
+ }
+ }
+
+ if (srv_config->acl_fn_dir) {
+ fd_dir = open(srv_config->acl_fn_dir, O_RDONLY);
+ if (fd_dir < 0) {
+ LOG(LOG_ERR, "acl_load: unable to open: %s\n", srv_config->acl_fn_dir);
+ close(fd);
+ return ECP_ERR;
+ }
+ }
+
+ pthread_mutex_lock(&acl_li_mutex);
+ if (fd >= 0) {
+ acl_new = acl_create_item();
+ rv = _read_file(fd, acl_new);
+ if (rv) {
+ LOG(LOG_ERR, "acl_load: read from file: %s err:%d\n", srv_config->acl_fn, rv);
+ acl_destroy_list(acl_new);
+ goto load_fin;
+ }
+ }
+
+ if (fd_dir >= 0) {
+ acl_dir_new = acl_create_item();
+ rv = _read_file(fd_dir, acl_dir_new);
+ if (rv) {
+ LOG(LOG_ERR, "acl_load: read from file: %s err:%d\n", srv_config->acl_fn_dir, rv);
+ acl_destroy_list(acl_dir_new);
+ acl_destroy_list(acl_new);
+ goto load_fin;
+ }
+ }
+ if (acl_new) {
+ acl_destroy_list(acl_head);
+ acl_head = acl_new;
+ }
+ if (acl_dir_new) {
+ acl_destroy_list(acl_head_dir);
+ acl_head_dir = acl_dir_new;
+ }
+
+ pthread_rwlock_wrlock(&acl_ht_rwlock);
+ if (acl_new) {
+ _rv = _li2ht(acl_new, 0);
+ if (_rv) rv = ECP_ERR;
+ }
+ if (acl_dir_new) {
+ _rv = _li2ht(acl_dir_new, 1);
+ if (_rv) rv = ECP_ERR;
+ }
+
+ pthread_rwlock_unlock(&acl_ht_rwlock);
+
+load_fin:
+ pthread_mutex_unlock(&acl_li_mutex);
+
+ close(fd_dir);
+ close(fd);
+
+ return rv;
+}
+
+int acl_init(void) {
+ int rv;
+
+ srv_config = srv_get_config();
+
+ rv = pthread_mutex_init(&acl_li_mutex, NULL);
+ if (rv) return ECP_ERR;
+
+ rv = pthread_rwlock_init(&acl_ht_rwlock, NULL);
+ if (rv) {
+ pthread_mutex_destroy(&acl_li_mutex);
+ return ECP_ERR;
+ }
+
+ acl_keys = ecp_ht_create_keys();
+ acl_keys_dir = ecp_ht_create_keys();
+ if ((acl_keys == NULL) || (acl_keys_dir == NULL)) {
+ pthread_rwlock_destroy(&acl_ht_rwlock);
+ pthread_mutex_destroy(&acl_li_mutex);
+ if (acl_keys_dir) ecp_ht_destroy(acl_keys_dir);
+ if (acl_keys) ecp_ht_destroy(acl_keys);
+ return ECP_ERR_ALLOC;
+ }
+
+ return ECP_OK;
+}