config.c revision 315600
14Srgrimes/*-
2233124Stijl * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru>
34Srgrimes * All rights reserved.
4233124Stijl *
54Srgrimes * Redistribution and use in source and binary forms, with or without
6233124Stijl * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD: stable/10/usr.sbin/nscd/config.c 315600 2017-03-20 00:55:24Z pfg $");
30
31#include <sys/stat.h>
32#include <sys/time.h>
33
34#include <assert.h>
35#include <math.h>
36#include <nsswitch.h>
37#include <pthread.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41
42#include "config.h"
43#include "debug.h"
44#include "log.h"
45
46/*
47 * Default entries, which always exist in the configuration
48 */
49const char *c_default_entries[6] = {
50	NSDB_PASSWD,
51	NSDB_GROUP,
52	NSDB_HOSTS,
53	NSDB_SERVICES,
54	NSDB_PROTOCOLS,
55	NSDB_RPC
56	};
57
58static int configuration_entry_cmp(const void *, const void *);
59static int configuration_entry_sort_cmp(const void *, const void *);
60static int configuration_entry_cache_mp_sort_cmp(const void *, const void *);
61static int configuration_entry_cache_mp_cmp(const void *, const void *);
62static int configuration_entry_cache_mp_part_cmp(const void *, const void *);
63static struct configuration_entry *create_configuration_entry(const char *,
64	struct timeval const *, struct timeval const *,
65	struct common_cache_entry_params const *,
66	struct common_cache_entry_params const *,
67	struct mp_cache_entry_params const *);
68
69static int
70configuration_entry_sort_cmp(const void *e1, const void *e2)
71{
72	return (strcmp((*((struct configuration_entry **)e1))->name,
73		(*((struct configuration_entry **)e2))->name
74		));
75}
76
77static int
78configuration_entry_cmp(const void *e1, const void *e2)
79{
80	return (strcmp((const char *)e1,
81		(*((struct configuration_entry **)e2))->name
82		));
83}
84
85static int
86configuration_entry_cache_mp_sort_cmp(const void *e1, const void *e2)
87{
88	return (strcmp((*((cache_entry *)e1))->params->entry_name,
89		(*((cache_entry *)e2))->params->entry_name
90		));
91}
92
93static int
94configuration_entry_cache_mp_cmp(const void *e1, const void *e2)
95{
96	return (strcmp((const char *)e1,
97		(*((cache_entry *)e2))->params->entry_name
98		));
99}
100
101static int
102configuration_entry_cache_mp_part_cmp(const void *e1, const void *e2)
103{
104	return (strncmp((const char *)e1,
105		(*((cache_entry *)e2))->params->entry_name,
106		strlen((const char *)e1)
107		));
108}
109
110static struct configuration_entry *
111create_configuration_entry(const char *name,
112	struct timeval const *common_timeout,
113	struct timeval const *mp_timeout,
114	struct common_cache_entry_params const *positive_params,
115	struct common_cache_entry_params const *negative_params,
116	struct mp_cache_entry_params const *mp_params)
117{
118	struct configuration_entry *retval;
119	size_t	size;
120	int res;
121
122	TRACE_IN(create_configuration_entry);
123	assert(name != NULL);
124	assert(positive_params != NULL);
125	assert(negative_params != NULL);
126	assert(mp_params != NULL);
127
128	retval = calloc(1,
129		sizeof(*retval));
130	assert(retval != NULL);
131
132	res = pthread_mutex_init(&retval->positive_cache_lock, NULL);
133	if (res != 0) {
134		free(retval);
135		LOG_ERR_2("create_configuration_entry",
136			"can't create positive cache lock");
137		TRACE_OUT(create_configuration_entry);
138		return (NULL);
139	}
140
141	res = pthread_mutex_init(&retval->negative_cache_lock, NULL);
142	if (res != 0) {
143		pthread_mutex_destroy(&retval->positive_cache_lock);
144		free(retval);
145		LOG_ERR_2("create_configuration_entry",
146			"can't create negative cache lock");
147		TRACE_OUT(create_configuration_entry);
148		return (NULL);
149	}
150
151	res = pthread_mutex_init(&retval->mp_cache_lock, NULL);
152	if (res != 0) {
153		pthread_mutex_destroy(&retval->positive_cache_lock);
154		pthread_mutex_destroy(&retval->negative_cache_lock);
155		free(retval);
156		LOG_ERR_2("create_configuration_entry",
157			"can't create negative cache lock");
158		TRACE_OUT(create_configuration_entry);
159		return (NULL);
160	}
161
162	memcpy(&retval->positive_cache_params, positive_params,
163		sizeof(struct common_cache_entry_params));
164	memcpy(&retval->negative_cache_params, negative_params,
165		sizeof(struct common_cache_entry_params));
166	memcpy(&retval->mp_cache_params, mp_params,
167		sizeof(struct mp_cache_entry_params));
168
169	size = strlen(name);
170	retval->name = calloc(1, size + 1);
171	assert(retval->name != NULL);
172	memcpy(retval->name, name, size);
173
174	memcpy(&retval->common_query_timeout, common_timeout,
175		sizeof(struct timeval));
176	memcpy(&retval->mp_query_timeout, mp_timeout,
177		sizeof(struct timeval));
178
179	asprintf(&retval->positive_cache_params.cep.entry_name, "%s+", name);
180	assert(retval->positive_cache_params.cep.entry_name != NULL);
181
182	asprintf(&retval->negative_cache_params.cep.entry_name, "%s-", name);
183	assert(retval->negative_cache_params.cep.entry_name != NULL);
184
185	asprintf(&retval->mp_cache_params.cep.entry_name, "%s*", name);
186	assert(retval->mp_cache_params.cep.entry_name != NULL);
187
188	TRACE_OUT(create_configuration_entry);
189	return (retval);
190}
191
192/*
193 * Creates configuration entry and fills it with default values
194 */
195struct configuration_entry *
196create_def_configuration_entry(const char *name)
197{
198	struct common_cache_entry_params positive_params, negative_params;
199	struct mp_cache_entry_params mp_params;
200	struct timeval default_common_timeout, default_mp_timeout;
201
202	struct configuration_entry *res = NULL;
203
204	TRACE_IN(create_def_configuration_entry);
205	memset(&positive_params, 0,
206		sizeof(struct common_cache_entry_params));
207	positive_params.cep.entry_type = CET_COMMON;
208	positive_params.cache_entries_size = DEFAULT_CACHE_HT_SIZE;
209	positive_params.max_elemsize = DEFAULT_POSITIVE_ELEMENTS_SIZE;
210	positive_params.satisf_elemsize = DEFAULT_POSITIVE_ELEMENTS_SIZE / 2;
211	positive_params.max_lifetime.tv_sec = DEFAULT_POSITIVE_LIFETIME;
212	positive_params.confidence_threshold = DEFAULT_POSITIVE_CONF_THRESH;
213	positive_params.policy = CPT_LRU;
214
215	memcpy(&negative_params, &positive_params,
216		sizeof(struct common_cache_entry_params));
217	negative_params.max_elemsize = DEFAULT_NEGATIVE_ELEMENTS_SIZE;
218	negative_params.satisf_elemsize = DEFAULT_NEGATIVE_ELEMENTS_SIZE / 2;
219	negative_params.max_lifetime.tv_sec = DEFAULT_NEGATIVE_LIFETIME;
220	negative_params.confidence_threshold = DEFAULT_NEGATIVE_CONF_THRESH;
221	negative_params.policy = CPT_FIFO;
222
223	memset(&default_common_timeout, 0, sizeof(struct timeval));
224	default_common_timeout.tv_sec = DEFAULT_COMMON_ENTRY_TIMEOUT;
225
226	memset(&default_mp_timeout, 0, sizeof(struct timeval));
227	default_mp_timeout.tv_sec = DEFAULT_MP_ENTRY_TIMEOUT;
228
229	memset(&mp_params, 0,
230		sizeof(struct mp_cache_entry_params));
231	mp_params.cep.entry_type = CET_MULTIPART;
232	mp_params.max_elemsize = DEFAULT_MULTIPART_ELEMENTS_SIZE;
233	mp_params.max_sessions = DEFAULT_MULITPART_SESSIONS_SIZE;
234	mp_params.max_lifetime.tv_sec = DEFAULT_MULITPART_LIFETIME;
235
236	res = create_configuration_entry(name, &default_common_timeout,
237		&default_mp_timeout, &positive_params, &negative_params,
238		&mp_params);
239
240	TRACE_OUT(create_def_configuration_entry);
241	return (res);
242}
243
244void
245destroy_configuration_entry(struct configuration_entry *entry)
246{
247	TRACE_IN(destroy_configuration_entry);
248	assert(entry != NULL);
249	pthread_mutex_destroy(&entry->positive_cache_lock);
250	pthread_mutex_destroy(&entry->negative_cache_lock);
251	pthread_mutex_destroy(&entry->mp_cache_lock);
252	free(entry->name);
253	free(entry->positive_cache_params.cep.entry_name);
254	free(entry->negative_cache_params.cep.entry_name);
255	free(entry->mp_cache_params.cep.entry_name);
256	free(entry->mp_cache_entries);
257	free(entry);
258	TRACE_OUT(destroy_configuration_entry);
259}
260
261int
262add_configuration_entry(struct configuration *config,
263	struct configuration_entry *entry)
264{
265	TRACE_IN(add_configuration_entry);
266	assert(entry != NULL);
267	assert(entry->name != NULL);
268	if (configuration_find_entry(config, entry->name) != NULL) {
269		TRACE_OUT(add_configuration_entry);
270		return (-1);
271	}
272
273	if (config->entries_size == config->entries_capacity) {
274		struct configuration_entry **new_entries;
275
276		config->entries_capacity *= 2;
277		new_entries = calloc(config->entries_capacity,
278			sizeof(*new_entries));
279		assert(new_entries != NULL);
280		memcpy(new_entries, config->entries,
281			sizeof(struct configuration_entry *) *
282		        config->entries_size);
283
284		free(config->entries);
285		config->entries = new_entries;
286	}
287
288	config->entries[config->entries_size++] = entry;
289	qsort(config->entries, config->entries_size,
290		sizeof(struct configuration_entry *),
291		configuration_entry_sort_cmp);
292
293	TRACE_OUT(add_configuration_entry);
294	return (0);
295}
296
297size_t
298configuration_get_entries_size(struct configuration *config)
299{
300	TRACE_IN(configuration_get_entries_size);
301	assert(config != NULL);
302	TRACE_OUT(configuration_get_entries_size);
303	return (config->entries_size);
304}
305
306struct configuration_entry *
307configuration_get_entry(struct configuration *config, size_t index)
308{
309	TRACE_IN(configuration_get_entry);
310	assert(config != NULL);
311	assert(index < config->entries_size);
312	TRACE_OUT(configuration_get_entry);
313	return (config->entries[index]);
314}
315
316struct configuration_entry *
317configuration_find_entry(struct configuration *config,
318	const char *name)
319{
320	struct configuration_entry	**retval;
321
322	TRACE_IN(configuration_find_entry);
323
324	retval = bsearch(name, config->entries, config->entries_size,
325		sizeof(struct configuration_entry *), configuration_entry_cmp);
326	TRACE_OUT(configuration_find_entry);
327
328	return ((retval != NULL) ? *retval : NULL);
329}
330
331/*
332 * All multipart cache entries are stored in the configuration_entry in the
333 * sorted array (sorted by names). The 3 functions below manage this array.
334 */
335
336int
337configuration_entry_add_mp_cache_entry(struct configuration_entry *config_entry,
338	cache_entry c_entry)
339{
340	cache_entry *new_mp_entries, *old_mp_entries;
341
342	TRACE_IN(configuration_entry_add_mp_cache_entry);
343	++config_entry->mp_cache_entries_size;
344	new_mp_entries = malloc(sizeof(*new_mp_entries) *
345		config_entry->mp_cache_entries_size);
346	assert(new_mp_entries != NULL);
347	new_mp_entries[0] = c_entry;
348
349	if (config_entry->mp_cache_entries_size - 1 > 0) {
350		memcpy(new_mp_entries + 1,
351		    config_entry->mp_cache_entries,
352		    (config_entry->mp_cache_entries_size - 1) *
353		    sizeof(cache_entry));
354	}
355
356	old_mp_entries = config_entry->mp_cache_entries;
357	config_entry->mp_cache_entries = new_mp_entries;
358	free(old_mp_entries);
359
360	qsort(config_entry->mp_cache_entries,
361		config_entry->mp_cache_entries_size,
362		sizeof(cache_entry),
363		configuration_entry_cache_mp_sort_cmp);
364
365	TRACE_OUT(configuration_entry_add_mp_cache_entry);
366	return (0);
367}
368
369cache_entry
370configuration_entry_find_mp_cache_entry(
371	struct configuration_entry *config_entry, const char *mp_name)
372{
373	cache_entry *result;
374
375	TRACE_IN(configuration_entry_find_mp_cache_entry);
376	result = bsearch(mp_name, config_entry->mp_cache_entries,
377		config_entry->mp_cache_entries_size,
378		sizeof(cache_entry), configuration_entry_cache_mp_cmp);
379
380	if (result == NULL) {
381		TRACE_OUT(configuration_entry_find_mp_cache_entry);
382		return (NULL);
383	} else {
384		TRACE_OUT(configuration_entry_find_mp_cache_entry);
385		return (*result);
386	}
387}
388
389/*
390 * Searches for all multipart entries with names starting with mp_name.
391 * Needed for cache flushing.
392 */
393int
394configuration_entry_find_mp_cache_entries(
395	struct configuration_entry *config_entry, const char *mp_name,
396	cache_entry **start, cache_entry **finish)
397{
398	cache_entry *result;
399
400	TRACE_IN(configuration_entry_find_mp_cache_entries);
401	result = bsearch(mp_name, config_entry->mp_cache_entries,
402		config_entry->mp_cache_entries_size,
403		sizeof(cache_entry), configuration_entry_cache_mp_part_cmp);
404
405	if (result == NULL) {
406		TRACE_OUT(configuration_entry_find_mp_cache_entries);
407		return (-1);
408	}
409
410	*start = result;
411	*finish = result + 1;
412
413	while (*start != config_entry->mp_cache_entries) {
414	    if (configuration_entry_cache_mp_part_cmp(mp_name, *start - 1) == 0)
415		*start = *start - 1;
416	    else
417		break;
418	}
419
420	while (*finish != config_entry->mp_cache_entries +
421		config_entry->mp_cache_entries_size) {
422
423	    if (configuration_entry_cache_mp_part_cmp(
424		mp_name, *finish) == 0)
425	    	*finish = *finish + 1;
426	    else
427		break;
428	}
429
430	TRACE_OUT(configuration_entry_find_mp_cache_entries);
431	return (0);
432}
433
434/*
435 * Configuration entry uses rwlock to handle access to its fields.
436 */
437void
438configuration_lock_rdlock(struct configuration *config)
439{
440    TRACE_IN(configuration_lock_rdlock);
441    pthread_rwlock_rdlock(&config->rwlock);
442    TRACE_OUT(configuration_lock_rdlock);
443}
444
445void
446configuration_lock_wrlock(struct configuration *config)
447{
448    TRACE_IN(configuration_lock_wrlock);
449    pthread_rwlock_wrlock(&config->rwlock);
450    TRACE_OUT(configuration_lock_wrlock);
451}
452
453void
454configuration_unlock(struct configuration *config)
455{
456    TRACE_IN(configuration_unlock);
457    pthread_rwlock_unlock(&config->rwlock);
458    TRACE_OUT(configuration_unlock);
459}
460
461/*
462 * Configuration entry uses 3 mutexes to handle cache operations. They are
463 * acquired by configuration_lock_entry and configuration_unlock_entry
464 * functions.
465 */
466void
467configuration_lock_entry(struct configuration_entry *entry,
468	enum config_entry_lock_type lock_type)
469{
470	TRACE_IN(configuration_lock_entry);
471	assert(entry != NULL);
472
473	switch (lock_type) {
474	case CELT_POSITIVE:
475		pthread_mutex_lock(&entry->positive_cache_lock);
476		break;
477	case CELT_NEGATIVE:
478		pthread_mutex_lock(&entry->negative_cache_lock);
479		break;
480	case CELT_MULTIPART:
481		pthread_mutex_lock(&entry->mp_cache_lock);
482		break;
483	default:
484		/* should be unreachable */
485		break;
486	}
487	TRACE_OUT(configuration_lock_entry);
488}
489
490void
491configuration_unlock_entry(struct configuration_entry *entry,
492	enum config_entry_lock_type lock_type)
493{
494	TRACE_IN(configuration_unlock_entry);
495	assert(entry != NULL);
496
497	switch (lock_type) {
498	case CELT_POSITIVE:
499		pthread_mutex_unlock(&entry->positive_cache_lock);
500		break;
501	case CELT_NEGATIVE:
502		pthread_mutex_unlock(&entry->negative_cache_lock);
503		break;
504	case CELT_MULTIPART:
505		pthread_mutex_unlock(&entry->mp_cache_lock);
506		break;
507	default:
508		/* should be unreachable */
509		break;
510	}
511	TRACE_OUT(configuration_unlock_entry);
512}
513
514struct configuration *
515init_configuration(void)
516{
517	struct configuration	*retval;
518
519	TRACE_IN(init_configuration);
520	retval = calloc(1, sizeof(*retval));
521	assert(retval != NULL);
522
523	retval->entries_capacity = INITIAL_ENTRIES_CAPACITY;
524	retval->entries = calloc(retval->entries_capacity,
525		sizeof(*retval->entries));
526	assert(retval->entries != NULL);
527
528	pthread_rwlock_init(&retval->rwlock, NULL);
529
530	TRACE_OUT(init_configuration);
531	return (retval);
532}
533
534void
535fill_configuration_defaults(struct configuration *config)
536{
537	size_t	len, i;
538
539	TRACE_IN(fill_configuration_defaults);
540	assert(config != NULL);
541
542	if (config->socket_path != NULL)
543		free(config->socket_path);
544
545	len = strlen(DEFAULT_SOCKET_PATH);
546	config->socket_path = calloc(1, len + 1);
547	assert(config->socket_path != NULL);
548	memcpy(config->socket_path, DEFAULT_SOCKET_PATH, len);
549
550	len = strlen(DEFAULT_PIDFILE_PATH);
551	config->pidfile_path = calloc(1, len + 1);
552	assert(config->pidfile_path != NULL);
553	memcpy(config->pidfile_path, DEFAULT_PIDFILE_PATH, len);
554
555	config->socket_mode =  S_IFSOCK | S_IRUSR | S_IWUSR |
556		S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
557	config->force_unlink = 1;
558
559	config->query_timeout = DEFAULT_QUERY_TIMEOUT;
560	config->threads_num = DEFAULT_THREADS_NUM;
561
562	for (i = 0; i < config->entries_size; ++i)
563		destroy_configuration_entry(config->entries[i]);
564	config->entries_size = 0;
565
566	TRACE_OUT(fill_configuration_defaults);
567}
568
569void
570destroy_configuration(struct configuration *config)
571{
572	unsigned int i;
573
574	TRACE_IN(destroy_configuration);
575	assert(config != NULL);
576	free(config->pidfile_path);
577	free(config->socket_path);
578
579	for (i = 0; i < config->entries_size; ++i)
580		destroy_configuration_entry(config->entries[i]);
581	free(config->entries);
582
583	pthread_rwlock_destroy(&config->rwlock);
584	free(config);
585	TRACE_OUT(destroy_configuration);
586}
587