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