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