xref: /freebsd/usr.sbin/nscd/config.c (revision 7bd6fde3951af84ef3b68e4d1eadc1840c2fc1b3)
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 *)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  */
191 struct configuration_entry *
192 create_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 
238 void
239 destroy_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 
255 int
256 add_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 
294 size_t
295 configuration_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 
303 struct configuration_entry *
304 configuration_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 
313 struct configuration_entry *
314 configuration_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 
333 int
334 configuration_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 
366 cache_entry
367 configuration_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  */
390 int
391 configuration_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  */
434 void
435 configuration_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 
442 void
443 configuration_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 
450 void
451 configuration_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  */
463 void
464 configuration_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 
487 void
488 configuration_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 
511 struct configuration *
512 init_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 
535 void
536 fill_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 
572 void
573 destroy_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