summaryrefslogtreecommitdiffstats
path: root/usr.sbin/nscd/config.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/nscd/config.c')
-rw-r--r--usr.sbin/nscd/config.c588
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..bc3eb49
--- /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 <assert.h>
+#include <math.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 = (struct configuration_entry *)malloc(
+ sizeof(struct configuration_entry));
+ assert(retval != NULL);
+ memset(retval, 0, sizeof(struct configuration_entry));
+
+ 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 = (char *)malloc(size + 1);
+ assert(retval->name != NULL);
+ memset(retval->name, 0, size + 1);
+ 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.entry_name, "%s+", name);
+ assert(retval->positive_cache_params.entry_name != NULL);
+
+ asprintf(&retval->negative_cache_params.entry_name, "%s-", name);
+ assert(retval->negative_cache_params.entry_name != NULL);
+
+ asprintf(&retval->mp_cache_params.entry_name, "%s*", name);
+ assert(retval->mp_cache_params.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.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.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.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.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.entry_name);
+ free(entry->negative_cache_params.entry_name);
+ free(entry->mp_cache_params.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 = (struct configuration_entry **)malloc(
+ sizeof(struct configuration_entry *) *
+ config->entries_capacity);
+ assert(new_entries != NULL);
+ memset(new_entries, 0, sizeof(struct configuration_entry *) *
+ config->entries_capacity);
+ 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 = (cache_entry *)malloc(sizeof(cache_entry) *
+ 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 = (struct configuration *)malloc(sizeof(struct configuration));
+ assert(retval != NULL);
+ memset(retval, 0, sizeof(struct configuration));
+
+ retval->entries_capacity = INITIAL_ENTRIES_CAPACITY;
+ retval->entries = (struct configuration_entry **)malloc(
+ sizeof(struct configuration_entry *) *
+ retval->entries_capacity);
+ assert(retval->entries != NULL);
+ memset(retval->entries, 0, sizeof(struct configuration_entry *) *
+ retval->entries_capacity);
+
+ 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 = (char *)malloc(len + 1);
+ assert(config->socket_path != NULL);
+ memset(config->socket_path, 0, len + 1);
+ memcpy(config->socket_path, DEFAULT_SOCKET_PATH, len);
+
+ len = strlen(DEFAULT_PIDFILE_PATH);
+ config->pidfile_path = (char *)malloc(len + 1);
+ assert(config->pidfile_path != NULL);
+ memset(config->pidfile_path, 0, len + 1);
+ 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)
+{
+ 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);
+}
OpenPOWER on IntegriCloud