]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - usr.sbin/nscd/config.c
MFC r318722:
[FreeBSD/stable/10.git] / usr.sbin / nscd / config.c
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
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
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
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
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
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 *
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 *
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
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
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(config->entries_capacity,
278                         sizeof(*new_entries));
279                 assert(new_entries != NULL);
280                 memcpy(new_entries, config->entries,
281                         sizeof(struct configuration_entry *) *
282                         config->entries_size);
283
284                 free(config->entries);
285                 config->entries = new_entries;
286         }
287
288         config->entries[config->entries_size++] = entry;
289         qsort(config->entries, config->entries_size,
290                 sizeof(struct configuration_entry *),
291                 configuration_entry_sort_cmp);
292
293         TRACE_OUT(add_configuration_entry);
294         return (0);
295 }
296
297 size_t
298 configuration_get_entries_size(struct configuration *config)
299 {
300         TRACE_IN(configuration_get_entries_size);
301         assert(config != NULL);
302         TRACE_OUT(configuration_get_entries_size);
303         return (config->entries_size);
304 }
305
306 struct configuration_entry *
307 configuration_get_entry(struct configuration *config, size_t index)
308 {
309         TRACE_IN(configuration_get_entry);
310         assert(config != NULL);
311         assert(index < config->entries_size);
312         TRACE_OUT(configuration_get_entry);
313         return (config->entries[index]);
314 }
315
316 struct configuration_entry *
317 configuration_find_entry(struct configuration *config,
318         const char *name)
319 {
320         struct configuration_entry      **retval;
321
322         TRACE_IN(configuration_find_entry);
323
324         retval = bsearch(name, config->entries, config->entries_size,
325                 sizeof(struct configuration_entry *), configuration_entry_cmp);
326         TRACE_OUT(configuration_find_entry);
327
328         return ((retval != NULL) ? *retval : NULL);
329 }
330
331 /*
332  * All multipart cache entries are stored in the configuration_entry in the
333  * sorted array (sorted by names). The 3 functions below manage this array.
334  */
335
336 int
337 configuration_entry_add_mp_cache_entry(struct configuration_entry *config_entry,
338         cache_entry c_entry)
339 {
340         cache_entry *new_mp_entries, *old_mp_entries;
341
342         TRACE_IN(configuration_entry_add_mp_cache_entry);
343         ++config_entry->mp_cache_entries_size;
344         new_mp_entries = malloc(sizeof(*new_mp_entries) *
345                 config_entry->mp_cache_entries_size);
346         assert(new_mp_entries != NULL);
347         new_mp_entries[0] = c_entry;
348
349         if (config_entry->mp_cache_entries_size - 1 > 0) {
350                 memcpy(new_mp_entries + 1,
351                     config_entry->mp_cache_entries,
352                     (config_entry->mp_cache_entries_size - 1) *
353                     sizeof(cache_entry));
354         }
355
356         old_mp_entries = config_entry->mp_cache_entries;
357         config_entry->mp_cache_entries = new_mp_entries;
358         free(old_mp_entries);
359
360         qsort(config_entry->mp_cache_entries,
361                 config_entry->mp_cache_entries_size,
362                 sizeof(cache_entry),
363                 configuration_entry_cache_mp_sort_cmp);
364
365         TRACE_OUT(configuration_entry_add_mp_cache_entry);
366         return (0);
367 }
368
369 cache_entry
370 configuration_entry_find_mp_cache_entry(
371         struct configuration_entry *config_entry, const char *mp_name)
372 {
373         cache_entry *result;
374
375         TRACE_IN(configuration_entry_find_mp_cache_entry);
376         result = bsearch(mp_name, config_entry->mp_cache_entries,
377                 config_entry->mp_cache_entries_size,
378                 sizeof(cache_entry), configuration_entry_cache_mp_cmp);
379
380         if (result == NULL) {
381                 TRACE_OUT(configuration_entry_find_mp_cache_entry);
382                 return (NULL);
383         } else {
384                 TRACE_OUT(configuration_entry_find_mp_cache_entry);
385                 return (*result);
386         }
387 }
388
389 /*
390  * Searches for all multipart entries with names starting with mp_name.
391  * Needed for cache flushing.
392  */
393 int
394 configuration_entry_find_mp_cache_entries(
395         struct configuration_entry *config_entry, const char *mp_name,
396         cache_entry **start, cache_entry **finish)
397 {
398         cache_entry *result;
399
400         TRACE_IN(configuration_entry_find_mp_cache_entries);
401         result = bsearch(mp_name, config_entry->mp_cache_entries,
402                 config_entry->mp_cache_entries_size,
403                 sizeof(cache_entry), configuration_entry_cache_mp_part_cmp);
404
405         if (result == NULL) {
406                 TRACE_OUT(configuration_entry_find_mp_cache_entries);
407                 return (-1);
408         }
409
410         *start = result;
411         *finish = result + 1;
412
413         while (*start != config_entry->mp_cache_entries) {
414             if (configuration_entry_cache_mp_part_cmp(mp_name, *start - 1) == 0)
415                 *start = *start - 1;
416             else
417                 break;
418         }
419
420         while (*finish != config_entry->mp_cache_entries +
421                 config_entry->mp_cache_entries_size) {
422
423             if (configuration_entry_cache_mp_part_cmp(
424                 mp_name, *finish) == 0)
425                 *finish = *finish + 1;
426             else
427                 break;
428         }
429
430         TRACE_OUT(configuration_entry_find_mp_cache_entries);
431         return (0);
432 }
433
434 /*
435  * Configuration entry uses rwlock to handle access to its fields.
436  */
437 void
438 configuration_lock_rdlock(struct configuration *config)
439 {
440     TRACE_IN(configuration_lock_rdlock);
441     pthread_rwlock_rdlock(&config->rwlock);
442     TRACE_OUT(configuration_lock_rdlock);
443 }
444
445 void
446 configuration_lock_wrlock(struct configuration *config)
447 {
448     TRACE_IN(configuration_lock_wrlock);
449     pthread_rwlock_wrlock(&config->rwlock);
450     TRACE_OUT(configuration_lock_wrlock);
451 }
452
453 void
454 configuration_unlock(struct configuration *config)
455 {
456     TRACE_IN(configuration_unlock);
457     pthread_rwlock_unlock(&config->rwlock);
458     TRACE_OUT(configuration_unlock);
459 }
460
461 /*
462  * Configuration entry uses 3 mutexes to handle cache operations. They are
463  * acquired by configuration_lock_entry and configuration_unlock_entry
464  * functions.
465  */
466 void
467 configuration_lock_entry(struct configuration_entry *entry,
468         enum config_entry_lock_type lock_type)
469 {
470         TRACE_IN(configuration_lock_entry);
471         assert(entry != NULL);
472
473         switch (lock_type) {
474         case CELT_POSITIVE:
475                 pthread_mutex_lock(&entry->positive_cache_lock);
476                 break;
477         case CELT_NEGATIVE:
478                 pthread_mutex_lock(&entry->negative_cache_lock);
479                 break;
480         case CELT_MULTIPART:
481                 pthread_mutex_lock(&entry->mp_cache_lock);
482                 break;
483         default:
484                 /* should be unreachable */
485                 break;
486         }
487         TRACE_OUT(configuration_lock_entry);
488 }
489
490 void
491 configuration_unlock_entry(struct configuration_entry *entry,
492         enum config_entry_lock_type lock_type)
493 {
494         TRACE_IN(configuration_unlock_entry);
495         assert(entry != NULL);
496
497         switch (lock_type) {
498         case CELT_POSITIVE:
499                 pthread_mutex_unlock(&entry->positive_cache_lock);
500                 break;
501         case CELT_NEGATIVE:
502                 pthread_mutex_unlock(&entry->negative_cache_lock);
503                 break;
504         case CELT_MULTIPART:
505                 pthread_mutex_unlock(&entry->mp_cache_lock);
506                 break;
507         default:
508                 /* should be unreachable */
509                 break;
510         }
511         TRACE_OUT(configuration_unlock_entry);
512 }
513
514 struct configuration *
515 init_configuration(void)
516 {
517         struct configuration    *retval;
518
519         TRACE_IN(init_configuration);
520         retval = calloc(1, sizeof(*retval));
521         assert(retval != NULL);
522
523         retval->entries_capacity = INITIAL_ENTRIES_CAPACITY;
524         retval->entries = calloc(retval->entries_capacity,
525                 sizeof(*retval->entries));
526         assert(retval->entries != NULL);
527
528         pthread_rwlock_init(&retval->rwlock, NULL);
529
530         TRACE_OUT(init_configuration);
531         return (retval);
532 }
533
534 void
535 fill_configuration_defaults(struct configuration *config)
536 {
537         size_t  len, i;
538
539         TRACE_IN(fill_configuration_defaults);
540         assert(config != NULL);
541
542         if (config->socket_path != NULL)
543                 free(config->socket_path);
544
545         len = strlen(DEFAULT_SOCKET_PATH);
546         config->socket_path = calloc(1, len + 1);
547         assert(config->socket_path != NULL);
548         memcpy(config->socket_path, DEFAULT_SOCKET_PATH, len);
549
550         len = strlen(DEFAULT_PIDFILE_PATH);
551         config->pidfile_path = calloc(1, len + 1);
552         assert(config->pidfile_path != NULL);
553         memcpy(config->pidfile_path, DEFAULT_PIDFILE_PATH, len);
554
555         config->socket_mode =  S_IFSOCK | S_IRUSR | S_IWUSR |
556                 S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
557         config->force_unlink = 1;
558
559         config->query_timeout = DEFAULT_QUERY_TIMEOUT;
560         config->threads_num = DEFAULT_THREADS_NUM;
561
562         for (i = 0; i < config->entries_size; ++i)
563                 destroy_configuration_entry(config->entries[i]);
564         config->entries_size = 0;
565
566         TRACE_OUT(fill_configuration_defaults);
567 }
568
569 void
570 destroy_configuration(struct configuration *config)
571 {
572         unsigned int i;
573
574         TRACE_IN(destroy_configuration);
575         assert(config != NULL);
576         free(config->pidfile_path);
577         free(config->socket_path);
578
579         for (i = 0; i < config->entries_size; ++i)
580                 destroy_configuration_entry(config->entries[i]);
581         free(config->entries);
582
583         pthread_rwlock_destroy(&config->rwlock);
584         free(config);
585         TRACE_OUT(destroy_configuration);
586 }