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