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