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