#include #include #include #include #include #include #include #include #include #include #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 roles) { int rv; if ((acl_keys == NULL) || (acl_keys_dir == NULL)) return ECP_ERR; if ((srv_config->roles & ECP_ROLE_DIR) || (srv_config->roles & roles & ECP_ROLE_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->roles & roles & ECP_ROLE_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; ikey_cnt; i++) { rv = _add_key(&head->key[i], is_dir ? ECP_ROLE_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->roles); 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); } unsigned int acl_count(void) { unsigned int r = 0; pthread_rwlock_rdlock(&acl_ht_rwlock); if (acl_keys) r = ecp_ht_count(acl_keys); pthread_rwlock_unlock(&acl_ht_rwlock); return r; } 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); } unsigned int acl_dir_count(void) { unsigned int r = 0; pthread_rwlock_rdlock(&acl_ht_rwlock); if (acl_keys) r = ecp_ht_count(acl_keys_dir); pthread_rwlock_unlock(&acl_ht_rwlock); return r; } 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; }