]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/nscd/config.c
sqlite3: Vendor import of sqlite3 3.43.1
[FreeBSD/FreeBSD.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 #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
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
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
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
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
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 *
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 *
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
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
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
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 *
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 *
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
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
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
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
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
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
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
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
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 *
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
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
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 }