xref: /dragonfly/usr.sbin/nscd/config.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
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
configuration_entry_sort_cmp(const void * e1,const void * e2)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
configuration_entry_cmp(const void * e1,const void * e2)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
configuration_entry_cache_mp_sort_cmp(const void * e1,const void * e2)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
configuration_entry_cache_mp_cmp(const void * e1,const void * e2)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
configuration_entry_cache_mp_part_cmp(const void * e1,const void * e2)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 *
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)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 *
create_def_configuration_entry(const char * name)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
destroy_configuration_entry(struct configuration_entry * entry)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
add_configuration_entry(struct configuration * config,struct configuration_entry * entry)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
configuration_get_entries_size(struct configuration * config)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 *
configuration_get_entry(struct configuration * config,size_t index)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 *
configuration_find_entry(struct configuration * config,const char * name)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
configuration_entry_add_mp_cache_entry(struct configuration_entry * config_entry,cache_entry c_entry)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
configuration_entry_find_mp_cache_entry(struct configuration_entry * config_entry,const char * mp_name)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
configuration_entry_find_mp_cache_entries(struct configuration_entry * config_entry,const char * mp_name,cache_entry ** start,cache_entry ** finish)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
configuration_lock_rdlock(struct configuration * config)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
configuration_lock_wrlock(struct configuration * config)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
configuration_unlock(struct configuration * config)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
configuration_lock_entry(struct configuration_entry * entry,enum config_entry_lock_type lock_type)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
configuration_unlock_entry(struct configuration_entry * entry,enum config_entry_lock_type lock_type)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 *
init_configuration(void)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
fill_configuration_defaults(struct configuration * config)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
destroy_configuration(struct configuration * config)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 }
578