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