diff options
Diffstat (limited to 'usr.sbin/nscd/config.c')
-rw-r--r-- | usr.sbin/nscd/config.c | 588 |
1 files changed, 588 insertions, 0 deletions
diff --git a/usr.sbin/nscd/config.c b/usr.sbin/nscd/config.c new file mode 100644 index 0000000..f44e986 --- /dev/null +++ b/usr.sbin/nscd/config.c @@ -0,0 +1,588 @@ +/*- + * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/stat.h> +#include <sys/time.h> + +#include <assert.h> +#include <math.h> +#include <nsswitch.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "config.h" +#include "debug.h" +#include "log.h" + +/* + * Default entries, which always exist in the configuration + */ +const char *c_default_entries[6] = { + NSDB_PASSWD, + NSDB_GROUP, + NSDB_HOSTS, + NSDB_SERVICES, + NSDB_PROTOCOLS, + NSDB_RPC + }; + +static int configuration_entry_cmp(const void *, const void *); +static int configuration_entry_sort_cmp(const void *, const void *); +static int configuration_entry_cache_mp_sort_cmp(const void *, const void *); +static int configuration_entry_cache_mp_cmp(const void *, const void *); +static int configuration_entry_cache_mp_part_cmp(const void *, const void *); +static struct configuration_entry *create_configuration_entry(const char *, + struct timeval const *, struct timeval const *, + struct common_cache_entry_params const *, + struct common_cache_entry_params const *, + struct mp_cache_entry_params const *); + +static int +configuration_entry_sort_cmp(const void *e1, const void *e2) +{ + return (strcmp((*((struct configuration_entry **)e1))->name, + (*((struct configuration_entry **)e2))->name + )); +} + +static int +configuration_entry_cmp(const void *e1, const void *e2) +{ + return (strcmp((const char *)e1, + (*((struct configuration_entry **)e2))->name + )); +} + +static int +configuration_entry_cache_mp_sort_cmp(const void *e1, const void *e2) +{ + return (strcmp((*((cache_entry *)e1))->params->entry_name, + (*((cache_entry *)e2))->params->entry_name + )); +} + +static int +configuration_entry_cache_mp_cmp(const void *e1, const void *e2) +{ + return (strcmp((const char *)e1, + (*((cache_entry *)e2))->params->entry_name + )); +} + +static int +configuration_entry_cache_mp_part_cmp(const void *e1, const void *e2) +{ + return (strncmp((const char *)e1, + (*((cache_entry *)e2))->params->entry_name, + strlen((const char *)e1) + )); +} + +static struct configuration_entry * +create_configuration_entry(const char *name, + struct timeval const *common_timeout, + struct timeval const *mp_timeout, + struct common_cache_entry_params const *positive_params, + struct common_cache_entry_params const *negative_params, + struct mp_cache_entry_params const *mp_params) +{ + struct configuration_entry *retval; + size_t size; + int res; + + TRACE_IN(create_configuration_entry); + assert(name != NULL); + assert(positive_params != NULL); + assert(negative_params != NULL); + assert(mp_params != NULL); + + retval = calloc(1, + sizeof(*retval)); + assert(retval != NULL); + + res = pthread_mutex_init(&retval->positive_cache_lock, NULL); + if (res != 0) { + free(retval); + LOG_ERR_2("create_configuration_entry", + "can't create positive cache lock"); + TRACE_OUT(create_configuration_entry); + return (NULL); + } + + res = pthread_mutex_init(&retval->negative_cache_lock, NULL); + if (res != 0) { + pthread_mutex_destroy(&retval->positive_cache_lock); + free(retval); + LOG_ERR_2("create_configuration_entry", + "can't create negative cache lock"); + TRACE_OUT(create_configuration_entry); + return (NULL); + } + + res = pthread_mutex_init(&retval->mp_cache_lock, NULL); + if (res != 0) { + pthread_mutex_destroy(&retval->positive_cache_lock); + pthread_mutex_destroy(&retval->negative_cache_lock); + free(retval); + LOG_ERR_2("create_configuration_entry", + "can't create negative cache lock"); + TRACE_OUT(create_configuration_entry); + return (NULL); + } + + memcpy(&retval->positive_cache_params, positive_params, + sizeof(struct common_cache_entry_params)); + memcpy(&retval->negative_cache_params, negative_params, + sizeof(struct common_cache_entry_params)); + memcpy(&retval->mp_cache_params, mp_params, + sizeof(struct mp_cache_entry_params)); + + size = strlen(name); + retval->name = calloc(1, size + 1); + assert(retval->name != NULL); + memcpy(retval->name, name, size); + + memcpy(&retval->common_query_timeout, common_timeout, + sizeof(struct timeval)); + memcpy(&retval->mp_query_timeout, mp_timeout, + sizeof(struct timeval)); + + asprintf(&retval->positive_cache_params.cep.entry_name, "%s+", name); + assert(retval->positive_cache_params.cep.entry_name != NULL); + + asprintf(&retval->negative_cache_params.cep.entry_name, "%s-", name); + assert(retval->negative_cache_params.cep.entry_name != NULL); + + asprintf(&retval->mp_cache_params.cep.entry_name, "%s*", name); + assert(retval->mp_cache_params.cep.entry_name != NULL); + + TRACE_OUT(create_configuration_entry); + return (retval); +} + +/* + * Creates configuration entry and fills it with default values + */ +struct configuration_entry * +create_def_configuration_entry(const char *name) +{ + struct common_cache_entry_params positive_params, negative_params; + struct mp_cache_entry_params mp_params; + struct timeval default_common_timeout, default_mp_timeout; + + struct configuration_entry *res = NULL; + + TRACE_IN(create_def_configuration_entry); + memset(&positive_params, 0, + sizeof(struct common_cache_entry_params)); + positive_params.cep.entry_type = CET_COMMON; + positive_params.cache_entries_size = DEFAULT_CACHE_HT_SIZE; + positive_params.max_elemsize = DEFAULT_POSITIVE_ELEMENTS_SIZE; + positive_params.satisf_elemsize = DEFAULT_POSITIVE_ELEMENTS_SIZE / 2; + positive_params.max_lifetime.tv_sec = DEFAULT_POSITIVE_LIFETIME; + positive_params.confidence_threshold = DEFAULT_POSITIVE_CONF_THRESH; + positive_params.policy = CPT_LRU; + + memcpy(&negative_params, &positive_params, + sizeof(struct common_cache_entry_params)); + negative_params.max_elemsize = DEFAULT_NEGATIVE_ELEMENTS_SIZE; + negative_params.satisf_elemsize = DEFAULT_NEGATIVE_ELEMENTS_SIZE / 2; + negative_params.max_lifetime.tv_sec = DEFAULT_NEGATIVE_LIFETIME; + negative_params.confidence_threshold = DEFAULT_NEGATIVE_CONF_THRESH; + negative_params.policy = CPT_FIFO; + + memset(&default_common_timeout, 0, sizeof(struct timeval)); + default_common_timeout.tv_sec = DEFAULT_COMMON_ENTRY_TIMEOUT; + + memset(&default_mp_timeout, 0, sizeof(struct timeval)); + default_mp_timeout.tv_sec = DEFAULT_MP_ENTRY_TIMEOUT; + + memset(&mp_params, 0, + sizeof(struct mp_cache_entry_params)); + mp_params.cep.entry_type = CET_MULTIPART; + mp_params.max_elemsize = DEFAULT_MULTIPART_ELEMENTS_SIZE; + mp_params.max_sessions = DEFAULT_MULITPART_SESSIONS_SIZE; + mp_params.max_lifetime.tv_sec = DEFAULT_MULITPART_LIFETIME; + + res = create_configuration_entry(name, &default_common_timeout, + &default_mp_timeout, &positive_params, &negative_params, + &mp_params); + + TRACE_OUT(create_def_configuration_entry); + return (res); +} + +void +destroy_configuration_entry(struct configuration_entry *entry) +{ + TRACE_IN(destroy_configuration_entry); + assert(entry != NULL); + pthread_mutex_destroy(&entry->positive_cache_lock); + pthread_mutex_destroy(&entry->negative_cache_lock); + pthread_mutex_destroy(&entry->mp_cache_lock); + free(entry->name); + free(entry->positive_cache_params.cep.entry_name); + free(entry->negative_cache_params.cep.entry_name); + free(entry->mp_cache_params.cep.entry_name); + free(entry->mp_cache_entries); + free(entry); + TRACE_OUT(destroy_configuration_entry); +} + +int +add_configuration_entry(struct configuration *config, + struct configuration_entry *entry) +{ + TRACE_IN(add_configuration_entry); + assert(entry != NULL); + assert(entry->name != NULL); + if (configuration_find_entry(config, entry->name) != NULL) { + TRACE_OUT(add_configuration_entry); + return (-1); + } + + if (config->entries_size == config->entries_capacity) { + struct configuration_entry **new_entries; + + config->entries_capacity *= 2; + new_entries = calloc(1, + sizeof(*new_entries) * + config->entries_capacity); + assert(new_entries != NULL); + memcpy(new_entries, config->entries, + sizeof(struct configuration_entry *) * + config->entries_size); + + free(config->entries); + config->entries = new_entries; + } + + config->entries[config->entries_size++] = entry; + qsort(config->entries, config->entries_size, + sizeof(struct configuration_entry *), + configuration_entry_sort_cmp); + + TRACE_OUT(add_configuration_entry); + return (0); +} + +size_t +configuration_get_entries_size(struct configuration *config) +{ + TRACE_IN(configuration_get_entries_size); + assert(config != NULL); + TRACE_OUT(configuration_get_entries_size); + return (config->entries_size); +} + +struct configuration_entry * +configuration_get_entry(struct configuration *config, size_t index) +{ + TRACE_IN(configuration_get_entry); + assert(config != NULL); + assert(index < config->entries_size); + TRACE_OUT(configuration_get_entry); + return (config->entries[index]); +} + +struct configuration_entry * +configuration_find_entry(struct configuration *config, + const char *name) +{ + struct configuration_entry **retval; + + TRACE_IN(configuration_find_entry); + + retval = bsearch(name, config->entries, config->entries_size, + sizeof(struct configuration_entry *), configuration_entry_cmp); + TRACE_OUT(configuration_find_entry); + + return ((retval != NULL) ? *retval : NULL); +} + +/* + * All multipart cache entries are stored in the configuration_entry in the + * sorted array (sorted by names). The 3 functions below manage this array. + */ + +int +configuration_entry_add_mp_cache_entry(struct configuration_entry *config_entry, + cache_entry c_entry) +{ + cache_entry *new_mp_entries, *old_mp_entries; + + TRACE_IN(configuration_entry_add_mp_cache_entry); + ++config_entry->mp_cache_entries_size; + new_mp_entries = malloc(sizeof(*new_mp_entries) * + config_entry->mp_cache_entries_size); + assert(new_mp_entries != NULL); + new_mp_entries[0] = c_entry; + + if (config_entry->mp_cache_entries_size - 1 > 0) { + memcpy(new_mp_entries + 1, + config_entry->mp_cache_entries, + (config_entry->mp_cache_entries_size - 1) * + sizeof(cache_entry)); + } + + old_mp_entries = config_entry->mp_cache_entries; + config_entry->mp_cache_entries = new_mp_entries; + free(old_mp_entries); + + qsort(config_entry->mp_cache_entries, + config_entry->mp_cache_entries_size, + sizeof(cache_entry), + configuration_entry_cache_mp_sort_cmp); + + TRACE_OUT(configuration_entry_add_mp_cache_entry); + return (0); +} + +cache_entry +configuration_entry_find_mp_cache_entry( + struct configuration_entry *config_entry, const char *mp_name) +{ + cache_entry *result; + + TRACE_IN(configuration_entry_find_mp_cache_entry); + result = bsearch(mp_name, config_entry->mp_cache_entries, + config_entry->mp_cache_entries_size, + sizeof(cache_entry), configuration_entry_cache_mp_cmp); + + if (result == NULL) { + TRACE_OUT(configuration_entry_find_mp_cache_entry); + return (NULL); + } else { + TRACE_OUT(configuration_entry_find_mp_cache_entry); + return (*result); + } +} + +/* + * Searches for all multipart entries with names starting with mp_name. + * Needed for cache flushing. + */ +int +configuration_entry_find_mp_cache_entries( + struct configuration_entry *config_entry, const char *mp_name, + cache_entry **start, cache_entry **finish) +{ + cache_entry *result; + + TRACE_IN(configuration_entry_find_mp_cache_entries); + result = bsearch(mp_name, config_entry->mp_cache_entries, + config_entry->mp_cache_entries_size, + sizeof(cache_entry), configuration_entry_cache_mp_part_cmp); + + if (result == NULL) { + TRACE_OUT(configuration_entry_find_mp_cache_entries); + return (-1); + } + + *start = result; + *finish = result + 1; + + while (*start != config_entry->mp_cache_entries) { + if (configuration_entry_cache_mp_part_cmp(mp_name, *start - 1) == 0) + *start = *start - 1; + else + break; + } + + while (*finish != config_entry->mp_cache_entries + + config_entry->mp_cache_entries_size) { + + if (configuration_entry_cache_mp_part_cmp( + mp_name, *finish) == 0) + *finish = *finish + 1; + else + break; + } + + TRACE_OUT(configuration_entry_find_mp_cache_entries); + return (0); +} + +/* + * Configuration entry uses rwlock to handle access to its fields. + */ +void +configuration_lock_rdlock(struct configuration *config) +{ + TRACE_IN(configuration_lock_rdlock); + pthread_rwlock_rdlock(&config->rwlock); + TRACE_OUT(configuration_lock_rdlock); +} + +void +configuration_lock_wrlock(struct configuration *config) +{ + TRACE_IN(configuration_lock_wrlock); + pthread_rwlock_wrlock(&config->rwlock); + TRACE_OUT(configuration_lock_wrlock); +} + +void +configuration_unlock(struct configuration *config) +{ + TRACE_IN(configuration_unlock); + pthread_rwlock_unlock(&config->rwlock); + TRACE_OUT(configuration_unlock); +} + +/* + * Configuration entry uses 3 mutexes to handle cache operations. They are + * acquired by configuration_lock_entry and configuration_unlock_entry + * functions. + */ +void +configuration_lock_entry(struct configuration_entry *entry, + enum config_entry_lock_type lock_type) +{ + TRACE_IN(configuration_lock_entry); + assert(entry != NULL); + + switch (lock_type) { + case CELT_POSITIVE: + pthread_mutex_lock(&entry->positive_cache_lock); + break; + case CELT_NEGATIVE: + pthread_mutex_lock(&entry->negative_cache_lock); + break; + case CELT_MULTIPART: + pthread_mutex_lock(&entry->mp_cache_lock); + break; + default: + /* should be unreachable */ + break; + } + TRACE_OUT(configuration_lock_entry); +} + +void +configuration_unlock_entry(struct configuration_entry *entry, + enum config_entry_lock_type lock_type) +{ + TRACE_IN(configuration_unlock_entry); + assert(entry != NULL); + + switch (lock_type) { + case CELT_POSITIVE: + pthread_mutex_unlock(&entry->positive_cache_lock); + break; + case CELT_NEGATIVE: + pthread_mutex_unlock(&entry->negative_cache_lock); + break; + case CELT_MULTIPART: + pthread_mutex_unlock(&entry->mp_cache_lock); + break; + default: + /* should be unreachable */ + break; + } + TRACE_OUT(configuration_unlock_entry); +} + +struct configuration * +init_configuration(void) +{ + struct configuration *retval; + + TRACE_IN(init_configuration); + retval = calloc(1, sizeof(*retval)); + assert(retval != NULL); + + retval->entries_capacity = INITIAL_ENTRIES_CAPACITY; + retval->entries = calloc(1, + sizeof(*retval->entries) * + retval->entries_capacity); + assert(retval->entries != NULL); + + pthread_rwlock_init(&retval->rwlock, NULL); + + TRACE_OUT(init_configuration); + return (retval); +} + +void +fill_configuration_defaults(struct configuration *config) +{ + size_t len, i; + + TRACE_IN(fill_configuration_defaults); + assert(config != NULL); + + if (config->socket_path != NULL) + free(config->socket_path); + + len = strlen(DEFAULT_SOCKET_PATH); + config->socket_path = calloc(1, len + 1); + assert(config->socket_path != NULL); + memcpy(config->socket_path, DEFAULT_SOCKET_PATH, len); + + len = strlen(DEFAULT_PIDFILE_PATH); + config->pidfile_path = calloc(1, len + 1); + assert(config->pidfile_path != NULL); + memcpy(config->pidfile_path, DEFAULT_PIDFILE_PATH, len); + + config->socket_mode = S_IFSOCK | S_IRUSR | S_IWUSR | + S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; + config->force_unlink = 1; + + config->query_timeout = DEFAULT_QUERY_TIMEOUT; + config->threads_num = DEFAULT_THREADS_NUM; + + for (i = 0; i < config->entries_size; ++i) + destroy_configuration_entry(config->entries[i]); + config->entries_size = 0; + + TRACE_OUT(fill_configuration_defaults); +} + +void +destroy_configuration(struct configuration *config) +{ + unsigned int i; + + TRACE_IN(destroy_configuration); + assert(config != NULL); + free(config->pidfile_path); + free(config->socket_path); + + for (i = 0; i < config->entries_size; ++i) + destroy_configuration_entry(config->entries[i]); + free(config->entries); + + pthread_rwlock_destroy(&config->rwlock); + free(config); + TRACE_OUT(destroy_configuration); +} |