]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/nscd/parser.c
Add ELF flag to disable ASLR stack gap.
[FreeBSD/FreeBSD.git] / usr.sbin / nscd / parser.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/time.h>
32
33 #include <assert.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37
38 #include "config.h"
39 #include "debug.h"
40 #include "log.h"
41 #include "parser.h"
42
43 static void enable_cache(struct configuration *,const char *, int);
44 static struct configuration_entry *find_create_entry(struct configuration *,
45         const char *);
46 static int get_number(const char *, int, int);
47 static enum cache_policy_t get_policy(const char *);
48 static int get_yesno(const char *);
49 static int check_cachename(const char *);
50 static void check_files(struct configuration *, const char *, int);
51 static void set_keep_hot_count(struct configuration *, const char *, int);
52 static void set_negative_policy(struct configuration *, const char *,
53         enum cache_policy_t);
54 static void set_negative_time_to_live(struct configuration *,
55         const char *, int);
56 static void set_positive_policy(struct configuration *, const char *,
57         enum cache_policy_t);
58 static void set_perform_actual_lookups(struct configuration *, const char *,
59         int);
60 static void set_positive_time_to_live(struct configuration *,
61         const char *, int);
62 static void set_suggested_size(struct configuration *, const char *,
63         int size);
64 static void set_threads_num(struct configuration *, int);
65 static int strbreak(char *, char **, int);
66
67 static int
68 strbreak(char *str, char **fields, int fields_size)
69 {
70         char    *c = str;
71         int     i, num;
72
73         TRACE_IN(strbreak);
74         num = 0;
75         for (i = 0;
76              ((*fields =
77                 strsep(i < fields_size ? &c : NULL, "\n\t ")) != NULL);
78              ++i)
79                 if ((*(*fields)) != '\0') {
80                         ++fields;
81                         ++num;
82                 }
83
84         TRACE_OUT(strbreak);
85         return (num);
86 }
87
88 /*
89  * Tries to find the configuration entry with the specified name. If search
90  * fails, the new entry with the default parameters will be created.
91  */
92 static struct configuration_entry *
93 find_create_entry(struct configuration *config,
94         const char *entry_name)
95 {
96         struct configuration_entry *entry = NULL;
97         int res;
98
99         TRACE_IN(find_create_entry);
100         entry = configuration_find_entry(config, entry_name);
101         if (entry == NULL) {
102                 entry = create_def_configuration_entry(entry_name);
103                 assert( entry != NULL);
104                 res = add_configuration_entry(config, entry);
105                 assert(res == 0);
106         }
107
108         TRACE_OUT(find_create_entry);
109         return (entry);
110 }
111
112 /*
113  * The vast majority of the functions below corresponds to the particular
114  * keywords in the configuration file.
115  */
116 static void
117 enable_cache(struct configuration *config, const char *entry_name, int flag)
118 {
119         struct configuration_entry      *entry;
120
121         TRACE_IN(enable_cache);
122         entry = find_create_entry(config, entry_name);
123         entry->enabled = flag;
124         TRACE_OUT(enable_cache);
125 }
126
127 static void
128 set_positive_time_to_live(struct configuration *config,
129         const char *entry_name, int ttl)
130 {
131         struct configuration_entry *entry;
132         struct timeval lifetime;
133
134         TRACE_IN(set_positive_time_to_live);
135         assert(ttl >= 0);
136         assert(entry_name != NULL);
137         memset(&lifetime, 0, sizeof(struct timeval));
138         lifetime.tv_sec = ttl;
139
140         entry = find_create_entry(config, entry_name);
141         memcpy(&entry->positive_cache_params.max_lifetime,
142                 &lifetime, sizeof(struct timeval));
143         memcpy(&entry->mp_cache_params.max_lifetime,
144                 &lifetime, sizeof(struct timeval));
145
146         TRACE_OUT(set_positive_time_to_live);
147 }
148
149 static void
150 set_negative_time_to_live(struct configuration *config,
151         const char *entry_name, int nttl)
152 {
153         struct configuration_entry *entry;
154         struct timeval lifetime;
155
156         TRACE_IN(set_negative_time_to_live);
157         assert(nttl > 0);
158         assert(entry_name != NULL);
159         memset(&lifetime, 0, sizeof(struct timeval));
160         lifetime.tv_sec = nttl;
161
162         entry = find_create_entry(config, entry_name);
163         assert(entry != NULL);
164         memcpy(&entry->negative_cache_params.max_lifetime,
165                 &lifetime, sizeof(struct timeval));
166
167         TRACE_OUT(set_negative_time_to_live);
168 }
169
170 static void
171 set_positive_confidence_threshold(struct configuration *config,
172         const char *entry_name, int conf_thresh)
173 {
174         struct configuration_entry *entry;
175
176         TRACE_IN(set_positive_conf_thresh);
177         assert(conf_thresh > 0);
178         assert(entry_name != NULL);
179
180         entry = find_create_entry(config, entry_name);
181         assert(entry != NULL);
182         entry->positive_cache_params.confidence_threshold = conf_thresh;
183
184         TRACE_OUT(set_positive_conf_thresh);
185 }
186
187 static void
188 set_negative_confidence_threshold(struct configuration *config,
189         const char *entry_name, int conf_thresh)
190 {
191         struct configuration_entry *entry;
192
193         TRACE_IN(set_negative_conf_thresh);
194         assert(conf_thresh > 0);
195         assert(entry_name != NULL);
196         entry = find_create_entry(config, entry_name);
197         assert(entry != NULL);
198         entry->negative_cache_params.confidence_threshold = conf_thresh;
199         TRACE_OUT(set_negative_conf_thresh);
200 }
201
202 /*
203  * Hot count is actually the elements size limit.
204  */
205 static void
206 set_keep_hot_count(struct configuration *config,
207         const char *entry_name, int count)
208 {
209         struct configuration_entry *entry;
210
211         TRACE_IN(set_keep_hot_count);
212         assert(count >= 0);
213         assert(entry_name != NULL);
214
215         entry = find_create_entry(config, entry_name);
216         assert(entry != NULL);
217         entry->positive_cache_params.max_elemsize = count;
218
219         entry = find_create_entry(config, entry_name);
220         assert(entry != NULL);
221         entry->negative_cache_params.max_elemsize = count;
222
223         TRACE_OUT(set_keep_hot_count);
224 }
225
226 static void
227 set_positive_policy(struct configuration *config,
228         const char *entry_name, enum cache_policy_t policy)
229 {
230         struct configuration_entry *entry;
231
232         TRACE_IN(set_positive_policy);
233         assert(entry_name != NULL);
234
235         entry = find_create_entry(config, entry_name);
236         assert(entry != NULL);
237         entry->positive_cache_params.policy = policy;
238
239         TRACE_OUT(set_positive_policy);
240 }
241
242 static void
243 set_negative_policy(struct configuration *config,
244         const char *entry_name, enum cache_policy_t policy)
245 {
246         struct configuration_entry *entry;
247
248         TRACE_IN(set_negative_policy);
249         assert(entry_name != NULL);
250
251         entry = find_create_entry(config, entry_name);
252         assert(entry != NULL);
253         entry->negative_cache_params.policy = policy;
254
255         TRACE_OUT(set_negative_policy);
256 }
257
258 static void
259 set_perform_actual_lookups(struct configuration *config,
260         const char *entry_name, int flag)
261 {
262         struct configuration_entry *entry;
263
264         TRACE_IN(set_perform_actual_lookups);
265         assert(entry_name != NULL);
266
267         entry = find_create_entry(config, entry_name);
268         assert(entry != NULL);
269         entry->perform_actual_lookups = flag;
270
271         TRACE_OUT(set_perform_actual_lookups);
272 }
273
274 static void
275 set_suggested_size(struct configuration *config,
276         const char *entry_name, int size)
277 {
278         struct configuration_entry      *entry;
279
280         TRACE_IN(set_suggested_size);
281         assert(config != NULL);
282         assert(entry_name != NULL);
283         assert(size > 0);
284
285         entry = find_create_entry(config, entry_name);
286         assert(entry != NULL);
287         entry->positive_cache_params.cache_entries_size = size;
288         entry->negative_cache_params.cache_entries_size = size;
289
290         TRACE_OUT(set_suggested_size);
291 }
292
293 static void
294 check_files(struct configuration *config, const char *entry_name, int flag)
295 {
296
297         TRACE_IN(check_files);
298         assert(entry_name != NULL);
299         TRACE_OUT(check_files);
300 }
301
302 static int
303 get_yesno(const char *str)
304 {
305
306         if (strcmp(str, "yes") == 0)
307                 return (1);
308         else if (strcmp(str, "no") == 0)
309                 return (0);
310         else
311                 return (-1);
312 }
313
314 static int
315 get_number(const char *str, int low, int max)
316 {
317
318         char *end = NULL;
319         int res = 0;
320
321         if (str[0] == '\0')
322                 return (-1);
323
324         res = strtol(str, &end, 10);
325         if (*end != '\0')
326                 return (-1);
327         else
328                 if (((res >= low) || (low == -1)) &&
329                         ((res <= max) || (max == -1)))
330                         return (res);
331                 else
332                         return (-2);
333 }
334
335 static enum cache_policy_t
336 get_policy(const char *str)
337 {
338
339         if (strcmp(str, "fifo") == 0)
340                 return (CPT_FIFO);
341         else if (strcmp(str, "lru") == 0)
342                 return (CPT_LRU);
343         else if (strcmp(str, "lfu") == 0)
344                 return (CPT_LFU);
345
346         return (-1);
347 }
348
349 static int
350 check_cachename(const char *str)
351 {
352
353         assert(str != NULL);
354         return ((strlen(str) > 0) ? 0 : -1);
355 }
356
357 static void
358 set_threads_num(struct configuration *config, int value)
359 {
360
361         assert(config != NULL);
362         config->threads_num = value;
363 }
364
365 /*
366  * The main configuration routine. Its implementation is hugely inspired by the
367  * the same routine implementation in Solaris NSCD.
368  */
369 int
370 parse_config_file(struct configuration *config,
371         const char *fname, char const **error_str, int *error_line)
372 {
373         FILE    *fin;
374         char    buffer[255];
375         char    *fields[128];
376         int     field_count, line_num, value;
377         int     res;
378         int     invalid_value;
379
380         TRACE_IN(parse_config_file);
381         assert(config != NULL);
382         assert(fname != NULL);
383
384         fin = fopen(fname, "r");
385         if (fin == NULL) {
386                 TRACE_OUT(parse_config_file);
387                 return (-1);
388         }
389
390         res = 0;
391         line_num = 0;
392         invalid_value = 0;
393         memset(buffer, 0, sizeof(buffer));
394         while ((res == 0) && (fgets(buffer, sizeof(buffer) - 1, fin) != NULL)) {
395                 field_count = strbreak(buffer, fields, sizeof(fields));
396                 ++line_num;
397
398                 if (field_count == 0)
399                         continue;
400
401                 switch (fields[0][0]) {
402                 case '#':
403                 case '\0':
404                         continue;
405                 case 'e':
406                         if ((field_count == 3) &&
407                         (strcmp(fields[0], "enable-cache") == 0) &&
408                         (check_cachename(fields[1]) == 0) &&
409                         ((value = get_yesno(fields[2])) != -1)) {
410                                 enable_cache(config, fields[1], value);
411                                 continue;
412                         }
413                         break;
414                 case 'd':
415                         if ((field_count == 2) &&
416                         (strcmp(fields[0], "debug-level") == 0) &&
417                         ((value = get_number(fields[1], 0, 10)) != -1)) {
418                                 continue;
419                         }
420                         break;
421                 case 'p':
422                         if ((field_count == 3) &&
423                         (strcmp(fields[0], "positive-time-to-live") == 0) &&
424                         (check_cachename(fields[1]) == 0) &&
425                         ((value = get_number(fields[2], 0, -1)) != -1)) {
426                                 if (value <= 0) {
427                                         invalid_value = 1;
428                                         break;
429                                 }
430                                 set_positive_time_to_live(config,
431                                         fields[1], value);
432                                 continue;
433                         } else if ((field_count == 3) &&
434                         (strcmp(fields[0], "positive-confidence-threshold") == 0) &&
435                         ((value = get_number(fields[2], 1, -1)) != -1)) {
436                                 if (value <= 0) {
437                                         invalid_value = 1;
438                                         break;
439                                 }
440                                 set_positive_confidence_threshold(config,
441                                         fields[1], value);
442                                 continue;
443                         } else if ((field_count == 3) &&
444                         (strcmp(fields[0], "positive-policy") == 0) &&
445                         (check_cachename(fields[1]) == 0) &&
446                         ((value = get_policy(fields[2])) != -1)) {
447                                 set_positive_policy(config, fields[1], value);
448                                 continue;
449                         } else if ((field_count == 3) &&
450                         (strcmp(fields[0], "perform-actual-lookups") == 0) &&
451                         (check_cachename(fields[1]) == 0) &&
452                         ((value = get_yesno(fields[2])) != -1)) {
453                                 set_perform_actual_lookups(config, fields[1],
454                                         value);
455                                 continue;
456                         }
457                         break;
458                 case 'n':
459                         if ((field_count == 3) &&
460                         (strcmp(fields[0], "negative-time-to-live") == 0) &&
461                         (check_cachename(fields[1]) == 0) &&
462                         ((value = get_number(fields[2], 0, -1)) != -1)) {
463                                 if (value <= 0) {
464                                         invalid_value = 1;
465                                         break;
466                                 }
467                                 set_negative_time_to_live(config,
468                                         fields[1], value);
469                                 continue;
470                         } else if ((field_count == 3) &&
471                         (strcmp(fields[0], "negative-confidence-threshold") == 0) &&
472                         ((value = get_number(fields[2], 1, -1)) != -1)) {
473                                 if (value <= 0) {
474                                         invalid_value = 1;
475                                         break;
476                                 }
477                                 set_negative_confidence_threshold(config,
478                                         fields[1], value);
479                                 continue;
480                         } else if ((field_count == 3) &&
481                         (strcmp(fields[0], "negative-policy") == 0) &&
482                         (check_cachename(fields[1]) == 0) &&
483                         ((value = get_policy(fields[2])) != -1)) {
484                                 set_negative_policy(config,
485                                         fields[1], value);
486                                 continue;
487                         }
488                         break;
489                 case 's':
490                         if ((field_count == 3) &&
491                         (strcmp(fields[0], "suggested-size") == 0) &&
492                         (check_cachename(fields[1]) == 0) &&
493                         ((value = get_number(fields[2], 1, -1)) != -1)) {
494                                 if (value <= 0) {
495                                         invalid_value = 1;
496                                         break;
497                                 }
498                                 set_suggested_size(config, fields[1], value);
499                                 continue;
500                         }
501                         break;
502                 case 't':
503                         if ((field_count == 2) &&
504                         (strcmp(fields[0], "threads") == 0) &&
505                         ((value = get_number(fields[1], 1, -1)) != -1)) {
506                                 set_threads_num(config, value);
507                                 continue;
508                         }
509                         break;
510                 case 'k':
511                         if ((field_count == 3) &&
512                         (strcmp(fields[0], "keep-hot-count") == 0) &&
513                         (check_cachename(fields[1]) == 0) &&
514                         ((value = get_number(fields[2], 0, -1)) != -1)) {
515                                 if (value < 0) {
516                                         invalid_value = 1;
517                                         break;
518                                 }
519                                 set_keep_hot_count(config,
520                                         fields[1], value);
521                                 continue;
522                         }
523                         break;
524                 case 'c':
525                         if ((field_count == 3) &&
526                         (strcmp(fields[0], "check-files") == 0) &&
527                         (check_cachename(fields[1]) == 0) &&
528                         ((value = get_yesno(fields[2])) != -1)) {
529                                 check_files(config,
530                                         fields[1], value);
531                                 continue;
532                         }
533                         break;
534                 default:
535                         break;
536                 }
537
538                 if (invalid_value != 0) {
539                         LOG_ERR_2("Invalid value for parameter",
540                                 "error in file %s on line %d",
541                                 fname, line_num);
542                         *error_str = "invalid value";
543                 } else {
544                         LOG_ERR_2("config file parser", "error in file "
545                                 "%s on line %d", fname, line_num);
546                         *error_str = "syntax error";
547                 }
548                 *error_line = line_num;
549                 res = -1;
550         }
551         fclose(fin);
552
553         TRACE_OUT(parse_config_file);
554         return (res);
555 }