Fix help text and --keyparam.
[libpwmd.git] / src / rcfile.c
blobc895dcb9797af2104919001887ef44d009c34afb
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014
3 Ben Kibbey <bjk@luxsci.net>
5 This file is part of pwmd.
7 Pwmd is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 2 of the License, or
10 (at your option) any later version.
12 Pwmd is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Pwmd. If not, see <http://www.gnu.org/licenses/>.
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29 #include <errno.h>
30 #include <ctype.h>
31 #include <pwd.h>
33 #include "pwmd-error.h"
34 #include "mutex.h"
35 #include "rcfile.h"
36 #include "util-misc.h"
37 #include "common.h"
38 #include "util-slist.h"
39 #include "util-string.h"
40 #include "mem.h"
42 #define DEFAULT_CACHE_TIMEOUT "600"
43 #define DEFAULT_KEEPALIVE_INTERVAL "60"
45 #define INVALID_VALUE(file, line) do { \
46 if (file) \
47 log_write(_("%s(%i): invalid value for parameter."), file, line); \
48 } while (0);
50 enum
52 PARAM_INT, PARAM_CHARP, PARAM_LONG, PARAM_LONGLONG, PARAM_CHARPP,
53 PARAM_BOOL, PARAM_ULONG, PARAM_ULONGLONG
56 static struct config_params_s
58 char *name;
59 int type;
60 char *value;
61 } config_params[] = {
62 { "backup", PARAM_BOOL, "true"},
63 { "socket_path", PARAM_CHARP, NULL},
64 { "socket_perms", PARAM_CHARP, NULL},
65 { "passphrase", PARAM_CHARP, NULL},
66 { "passphrase_file", PARAM_CHARP, NULL},
67 { "log_path", PARAM_CHARP, "~/.pwmd/log"},
68 { "enable_logging", PARAM_BOOL, "0"},
69 { "log_keepopen", PARAM_BOOL, "true"},
70 { "log_level", PARAM_INT, "0"},
71 { "disable_mlockall", PARAM_BOOL, "true"},
72 { "cache_timeout", PARAM_INT, DEFAULT_CACHE_TIMEOUT},
73 { "cache_push", PARAM_CHARPP, NULL},
74 { "disable_list_and_dump", PARAM_BOOL, "false"},
75 { "recursion_depth", PARAM_INT, "100"},
76 { "syslog", PARAM_BOOL, "false"},
77 { "xfer_progress", PARAM_INT, "8196"},
78 { "allowed", PARAM_CHARPP, NULL},
79 { "allowed_file", PARAM_CHARP, NULL},
80 { "priority", PARAM_INT, INVALID_PRIORITY},
81 { "keepalive_interval", PARAM_INT, DEFAULT_KEEPALIVE_INTERVAL},
82 { "tcp_port", PARAM_INT, "6466"},
83 { "enable_tcp", PARAM_BOOL, "false"},
84 { "tcp_require_key", PARAM_BOOL, "false"},
85 { "tcp_wait", PARAM_INT, "0"},
86 { "tcp_bind", PARAM_CHARP, "any"},
87 { "tcp_interface", PARAM_CHARP, NULL},
88 { "tls_timeout", PARAM_INT, "300"},
89 { "tls_cipher_suite", PARAM_CHARP, "SECURE256"},
90 { "require_save_key", PARAM_BOOL, "true"},
91 { "invoking_user", PARAM_CHARP, NULL},
92 { "invoking_tls", PARAM_CHARP, NULL},
93 { "encrypt_to", PARAM_BOOL, "false"},
94 { "always_trust", PARAM_BOOL, "false"},
95 { "gpg_homedir", PARAM_CHARP, NULL},
96 { NULL, 0, NULL},
99 struct config_param_s
101 char *name;
102 int type;
103 union
105 int itype;
106 char *cptype;
107 char **cpptype;
108 long ltype;
109 long long lltype;
110 unsigned long ultype;
111 unsigned long long ulltype;
112 } value;
115 static struct config_section_s *config_find_section (struct slist_s *config,
116 const char *name);
117 static int new_param (struct config_section_s *section, const char *filename,
118 int lineno, const char *name, const char *value,
119 int type);
120 static void free_section (struct config_section_s *s);
121 static int set_defaults (struct slist_s **config);
123 static void
124 section_remove_param (struct config_section_s *section, const char *name)
126 unsigned i, t = slist_length (section->params);
128 for (i = 0; i < t; i++)
130 struct config_param_s *p = slist_nth_data (section->params, i);
132 if (!p)
133 continue;
135 if (!strcmp (p->name, name))
137 switch (p->type)
139 case PARAM_CHARP:
140 xfree (p->value.cptype);
141 break;
142 case PARAM_CHARPP:
143 strv_free (p->value.cpptype);
144 break;
147 section->params = slist_remove (section->params, p);
148 xfree (p->name);
149 xfree (p);
150 break;
155 void
156 config_clear_keys ()
158 MUTEX_LOCK (&rcfile_mutex);
159 unsigned i, t = slist_length (global_config);
161 for (i = 0; i < t; i++)
163 struct config_section_s *s = slist_nth_data (global_config, i);
164 if (!s)
165 continue;
167 section_remove_param (s, "passphrase");
170 MUTEX_UNLOCK (&rcfile_mutex);
173 static struct config_param_s *
174 config_has_param (struct config_section_s *s, const char *what)
176 unsigned i, t = slist_length (s->params);
178 for (i = 0; i < t; i++)
180 struct config_param_s *p = slist_nth_data (s->params, i);
181 if (!p)
182 break;
184 if (!strcmp (p->name, what))
185 return p;
188 return NULL;
191 static struct config_param_s *
192 config_get_param (struct slist_s *config,
193 const char *section, const char *what, int *exists)
195 unsigned i, t = slist_length (config);
197 *exists = 0;
199 for (i = 0; i < t; i++)
201 struct config_param_s *p;
202 struct config_section_s *s = slist_nth_data (config, i);
204 if (!s)
205 break;
207 if (strcmp (s->name, section))
208 continue;
210 p = config_has_param (s, what);
211 if (!p)
212 return NULL;
214 *exists = 1;
215 return p;
218 return NULL;
221 static struct config_section_s *
222 new_section (struct slist_s **config, const char *name)
224 struct slist_s *tmp;
225 struct config_section_s *s = xcalloc (1, sizeof (struct config_section_s));
227 if (!s)
228 return NULL;
230 s->name = str_dup (name);
231 if (!s->name)
233 log_write ("%s", pwmd_strerror (ENOMEM));
234 xfree (s);
235 return NULL;
238 tmp = slist_append (*config, s);
239 if (!tmp)
241 log_write ("%s", pwmd_strerror (ENOMEM));
242 xfree (s->name);
243 xfree (s);
244 return NULL;
247 *config = tmp;
248 return s;
252 config_set_string_param (struct slist_s **config, const char *section,
253 const char *name, const char *value)
255 struct config_section_s *s = config_find_section (*config, section);
257 if (!s)
259 s = new_section (config, section);
260 if (!s)
261 return 1;
264 return new_param (s, NULL, 0, name, value, PARAM_CHARP);
267 char *
268 config_get_string_param (struct slist_s *config, const char *section,
269 const char *what, int *exists)
271 struct config_param_s *p = config_get_param (config, section, what, exists);
272 return *exists && p->value.cptype ? str_dup (p->value.cptype) : NULL;
276 config_set_int_param (struct slist_s **config, const char *section,
277 const char *name, const char *value)
279 struct config_section_s *s = config_find_section (*config, section);
281 if (!s)
283 s = new_section (config, section);
284 if (!s)
285 return 1;
288 return new_param (s, NULL, 0, name, value, PARAM_INT);
292 config_get_int_param (struct slist_s *config, const char *section,
293 const char *what, int *exists)
295 struct config_param_s *p = config_get_param (config, section, what, exists);
296 return *exists ? p->value.itype : -1;
300 config_set_bool_param (struct slist_s **config, const char *section,
301 const char *name, const char *value)
303 struct config_section_s *s = config_find_section (*config, section);
305 if (!s)
307 s = new_section (config, section);
308 if (!s)
309 return 1;
312 return new_param (s, NULL, 0, name, value, PARAM_BOOL);
316 config_get_bool_param (struct slist_s *config, const char *section,
317 const char *what, int *exists)
319 return config_get_int_param (config, section, what, exists);
323 config_set_long_param (struct slist_s **config, const char *section,
324 const char *name, const char *value)
326 struct config_section_s *s = config_find_section (*config, section);
328 if (!s)
330 s = new_section (config, section);
331 if (!s)
332 return 1;
335 return new_param (s, NULL, 0, name, value, PARAM_LONG);
338 unsigned long
339 config_get_ulong_param (struct slist_s *config, const char *section,
340 const char *what, int *exists)
342 struct config_param_s *p = config_get_param (config, section, what, exists);
343 return *exists ? p->value.ultype : 0;
346 long
347 config_get_long_param (struct slist_s *config, const char *section,
348 const char *what, int *exists)
350 struct config_param_s *p = config_get_param (config, section, what, exists);
351 return *exists ? p->value.ltype : -1;
355 config_set_longlong_param (struct slist_s **config, const char *section,
356 const char *name, const char *value)
358 struct config_section_s *s = config_find_section (*config, section);
360 if (!s)
362 s = new_section (config, section);
363 if (!s)
364 return 1;
367 return new_param (s, NULL, 0, name, value, PARAM_LONGLONG);
370 long long
371 config_get_longlong_param (struct slist_s *config,
372 const char *section, const char *what, int *exists)
374 struct config_param_s *p = config_get_param (config, section, what, exists);
375 return *exists ? p->value.lltype : -1;
378 unsigned long long
379 config_get_ulonglong_param (struct slist_s *config,
380 const char *section,
381 const char *what, int *exists)
383 struct config_param_s *p = config_get_param (config, section, what, exists);
384 return *exists ? p->value.ulltype : 0;
388 config_set_list_param (struct slist_s **config, const char *section,
389 const char *name, const char *value)
391 struct config_section_s *s = config_find_section (*config, section);
393 if (!s)
395 s = new_section (config, section);
396 if (!s)
397 return 1;
400 return new_param (s, NULL, 0, name, value, PARAM_CHARPP);
403 char **
404 config_get_list_param (struct slist_s *config, const char *section,
405 const char *what, int *exists)
407 struct config_param_s *p = config_get_param (config, section, what, exists);
408 return *exists && p->value.cpptype ? strv_dup (p->value.cpptype) : NULL;
411 char *
412 config_get_string (const char *section, const char *what)
414 char *val = NULL;
415 const char *where = section ? section : "global";
416 int exists = 0;
418 MUTEX_LOCK (&rcfile_mutex);
419 val = config_get_string_param (global_config, where, what, &exists);
420 if (!exists && strcmp (section ? section : "", "global"))
421 val = config_get_string_param (global_config, "global", what, &exists);
423 MUTEX_UNLOCK (&rcfile_mutex);
424 return val;
427 char **
428 config_get_list (const char *section, const char *what)
430 char **val = NULL;
431 const char *where = section ? section : "global";
432 int exists = 0;
434 MUTEX_LOCK (&rcfile_mutex);
435 val = config_get_list_param (global_config, where, what, &exists);
436 if (!exists && strcmp (section ? section : "", "global"))
437 val = config_get_list_param (global_config, "global", what, &exists);
439 MUTEX_UNLOCK (&rcfile_mutex);
440 return val;
444 config_get_integer (const char *section, const char *what)
446 int val = 0;
447 const char *where = section ? section : "global";
448 int exists = 0;
450 MUTEX_LOCK (&rcfile_mutex);
451 val = config_get_int_param (global_config, where, what, &exists);
452 if (!exists && strcmp (section ? section : "", "global"))
453 val = config_get_int_param (global_config, "global", what, &exists);
455 MUTEX_UNLOCK (&rcfile_mutex);
456 return val;
459 long long
460 config_get_longlong (const char *section, const char *what)
462 long long val = 0;
463 const char *where = section ? section : "global";
464 int exists = 0;
466 MUTEX_LOCK (&rcfile_mutex);
467 val = config_get_longlong_param (global_config, where, what, &exists);
468 if (!exists && strcmp (section ? section : "", "global"))
469 val = config_get_longlong_param (global_config, "global", what, &exists);
471 MUTEX_UNLOCK (&rcfile_mutex);
472 return val;
475 unsigned long long
476 config_get_ulonglong (const char *section, const char *what)
478 unsigned long long val = 0;
479 const char *where = section ? section : "global";
480 int exists = 0;
482 MUTEX_LOCK (&rcfile_mutex);
483 val = config_get_ulonglong_param (global_config, where, what, &exists);
484 if (!exists && strcmp (section ? section : "", "global"))
485 val = config_get_ulonglong_param (global_config, "global", what, &exists);
487 MUTEX_UNLOCK (&rcfile_mutex);
488 return val;
491 long
492 config_get_long (const char *section, const char *what)
494 long val = 0;
495 const char *where = section ? section : "global";
496 int exists = 0;
498 MUTEX_LOCK (&rcfile_mutex);
499 val = config_get_long_param (global_config, where, what, &exists);
500 if (!exists && strcmp (section ? section : "", "global"))
501 val = config_get_long_param (global_config, "global", what, &exists);
503 MUTEX_UNLOCK (&rcfile_mutex);
504 return val;
507 unsigned long
508 config_get_ulong (const char *section, const char *what)
510 unsigned long val = 0;
511 const char *where = section ? section : "global";
512 int exists = 0;
514 MUTEX_LOCK (&rcfile_mutex);
515 val = config_get_ulong_param (global_config, where, what, &exists);
516 if (!exists && strcmp (section ? section : "", "global"))
517 val = config_get_ulong_param (global_config, "global", what, &exists);
519 MUTEX_UNLOCK (&rcfile_mutex);
520 return val;
524 config_get_boolean (const char *section, const char *what)
526 return config_get_integer (section, what);
529 char *
530 config_get_value (const char *section, const char *what)
532 const char *where = section ? section : "global";
533 int exists = 0;
534 int i;
535 int ival;
536 long lval;
537 long long llval;
538 unsigned long ulval;
539 unsigned long long ullval;
540 char *cpval;
541 char **cppval;
542 char *result = NULL;
544 MUTEX_LOCK (&rcfile_mutex);
546 for (i = 0; config_params[i].name; i++)
548 if (!strcmp (config_params[i].name, what))
550 switch (config_params[i].type)
552 case PARAM_BOOL:
553 case PARAM_INT:
554 ival = config_get_int_param (global_config, where, what,
555 &exists);
556 if (!exists && strcmp (section ? section : "", "global"))
557 ival = config_get_int_param (global_config, "global", what,
558 &exists);
559 result = str_asprintf ("%i", ival);
560 break;
561 case PARAM_CHARP:
562 cpval = config_get_string_param (global_config, where, what,
563 &exists);
564 if (!exists && strcmp (section ? section : "", "global"))
565 cpval =
566 config_get_string_param (global_config, "global", what,
567 &exists);
568 result = cpval;
569 break;
570 case PARAM_LONG:
571 lval = config_get_long_param (global_config, where, what,
572 &exists);
573 if (!exists && strcmp (section ? section : "", "global"))
574 lval = config_get_long_param (global_config, "global", what,
575 &exists);
576 result = str_asprintf ("%li", lval);
577 break;
578 case PARAM_ULONG:
579 ulval = config_get_ulong_param (global_config, where, what,
580 &exists);
581 if (!exists && strcmp (section ? section : "", "global"))
582 ulval = config_get_ulong_param (global_config, "global", what,
583 &exists);
584 result = str_asprintf ("%lu", ulval);
585 break;
586 case PARAM_LONGLONG:
587 llval = config_get_longlong_param (global_config, where, what,
588 &exists);
589 if (!exists && strcmp (section ? section : "", "global"))
590 llval = config_get_longlong_param (global_config, "global",
591 what, &exists);
592 result = str_asprintf ("%lli", llval);
593 break;
594 case PARAM_ULONGLONG:
595 ullval = config_get_ulonglong_param (global_config, where, what,
596 &exists);
597 if (!exists && strcmp (section ? section : "", "global"))
598 ullval = config_get_ulonglong_param (global_config, "global",
599 what, &exists);
600 result = str_asprintf ("%llu", ullval);
601 break;
602 case PARAM_CHARPP:
603 cppval = config_get_list_param (global_config, where, what,
604 &exists);
605 if (!exists && strcmp (section ? section : "", "global"))
606 cppval = config_get_list_param (global_config, "global", what,
607 &exists);
609 if (cppval)
610 result = strv_join (",", cppval);
612 strv_free (cppval);
613 break;
618 MUTEX_UNLOCK (&rcfile_mutex);
619 return result;
622 static void
623 parse_allowed_file (struct slist_s *config, const char *section)
625 FILE *fp;
626 char buf[LINE_MAX];
627 int exists;
628 char **list = NULL;
629 char *tmp;
630 char *p = config_get_string_param (config, section, "allowed_file", &exists);
632 if (!p || !*p)
634 xfree (p);
635 return;
638 tmp = expand_homedir (p);
639 xfree (p);
640 p = tmp;
641 fp = fopen (p, "r");
642 if (!fp)
644 log_write ("%s: %s", p, strerror (errno));
645 xfree (p);
646 return;
649 xfree (p);
650 list = config_get_list_param (config, section, "allowed", &exists);
651 if (!list && exists)
653 fclose (fp);
654 log_write ("%s", strerror (ENOMEM));
655 return;
658 while ((p = fgets (buf, sizeof (buf), fp)))
660 char **pp;
662 if (p[strlen(p)-1] == '\n')
663 p[strlen(p)-1] = 0;
665 while (*p && isspace (*p))
666 p++;
668 if (!*p)
669 continue;
671 tmp = str_dup (p);
672 if (tmp)
673 pp = strv_cat (list, str_dup (p));
675 if (!pp || !tmp)
677 xfree (tmp);
678 strv_free (list);
679 fclose (fp);
680 log_write ("%s", strerror (ENOMEM));
681 return;
684 xfree (tmp);
685 list = pp;
688 fclose(fp);
689 if (!list)
690 return;
692 p = strv_join (",", list);
693 strv_free (list);
695 if (!p)
697 log_write ("%s", strerror (ENOMEM));
698 return;
701 config_set_list_param (&config, section, "allowed", p);
702 xfree (p);
705 static int
706 fixup_allowed_once (struct slist_s **config, const char *section)
708 char **list, **pp, *p;
709 int exists;
711 parse_allowed_file (*config, section);
712 list = config_get_list_param (*config, section, "allowed", &exists);
713 for (pp = list; pp && *pp; pp++)
715 if (*(*pp) == '#')
717 for (p = *pp; p && *p; p++)
718 *p = toupper(*p);
722 strv_free (list);
723 if (!exists)
725 if (!strcmp (section, "global"))
727 p = get_username (getuid());
729 if (config_set_list_param (config, section, "allowed", p))
731 xfree (p);
732 return 1;
735 xfree (p);
737 else
739 list = config_get_list_param (*config, "global", "allowed", &exists);
740 if (list)
742 p = strv_join (",", list);
743 strv_free (list);
744 if (config_set_list_param (config, section, "allowed", p))
746 xfree (p);
747 return 1;
750 xfree (p);
755 return 0;
758 static int
759 fixup_allowed (struct slist_s **config)
761 int n, t = slist_length (*config);
763 for (n = 0; n < t; n++)
765 struct config_section_s *section;
767 section = slist_nth_data (*config, n);
768 if (fixup_allowed_once (config, section->name))
769 return 1;
772 return 0;
775 static int
776 set_defaults (struct slist_s **config)
778 char *s = NULL;
779 char **list;
780 int exists;
781 int i;
782 struct passwd *pwd;
784 for (i = 0; config_params[i].name; i++)
786 switch (config_params[i].type)
788 case PARAM_BOOL:
789 config_get_bool_param (*config, "global", config_params[i].name,
790 &exists);
791 if (!exists)
793 if (config_set_bool_param
794 (config, "global", config_params[i].name,
795 config_params[i].value))
796 goto fail;
798 break;
799 case PARAM_INT:
800 config_get_int_param (*config, "global", config_params[i].name,
801 &exists);
802 if (!exists)
804 if (config_set_int_param
805 (config, "global", config_params[i].name,
806 config_params[i].value))
807 goto fail;
809 break;
810 case PARAM_CHARP:
811 s = config_get_string_param (*config, "global",
812 config_params[i].name, &exists);
813 xfree (s);
814 if (!exists && config_params[i].value)
816 if (config_set_string_param (config, "global",
817 config_params[i].name,
818 config_params[i].value))
819 goto fail;
821 break;
822 case PARAM_CHARPP:
823 list = config_get_list_param (*config, "global",
824 config_params[i].name, &exists);
825 strv_free (list);
826 if (!exists && config_params[i].value)
828 if (config_set_list_param (config, "global",
829 config_params[i].name,
830 config_params[i].value))
831 goto fail;
833 break;
834 case PARAM_LONG:
835 config_get_long_param (*config, "global", config_params[i].name,
836 &exists);
837 if (!exists)
839 if (config_set_long_param
840 (config, "global", config_params[i].name,
841 config_params[i].value))
842 goto fail;
844 break;
845 case PARAM_LONGLONG:
846 config_get_longlong_param (*config, "global", config_params[i].name,
847 &exists);
848 if (!exists)
850 if (config_set_longlong_param (config, "global",
851 config_params[i].name,
852 config_params[i].value))
853 goto fail;
855 break;
859 s = NULL;
860 if (fixup_allowed (config))
861 goto fail;
863 max_recursion_depth = config_get_int_param (*config, "global",
864 "recursion_depth", &exists);
865 disable_list_and_dump = config_get_bool_param (*config, "global",
866 "disable_list_and_dump",
867 &exists);
868 #ifdef HAVE_MLOCKALL
869 disable_mlock =
870 config_get_bool_param (*config, "global", "disable_mlockall", &exists);
871 #endif
873 s = config_get_string_param(*config, "global", "invoking_user", &exists);
874 errno = 0;
875 if (!s || !*s)
876 pwd = getpwuid(getuid());
877 else
878 pwd = getpwnam(s);
880 if (!pwd)
882 log_write (_("could not set invoking user: user '%s' is invalid"), s);
883 goto fail;
886 xfree (s);
887 config_set_string_param(config, "global", "invoking_user", pwd->pw_name);
888 #ifdef WITH_GNUTLS
889 invoking_tls = config_get_string_param(*config, "global", "invoking_tls",
890 &exists);
891 for (char *p = invoking_tls; p && *p; p++)
892 *p = toupper(*p);
894 config_set_string_param(config, "global", "invoking_tls", invoking_tls);
895 #endif
896 invoking_uid = pwd->pw_uid;
897 invoking_gid = pwd->pw_gid;
898 return 0;
900 fail:
901 xfree (s);
902 return 1;
905 static struct config_section_s *
906 config_find_section (struct slist_s *config, const char *name)
908 unsigned i, t = slist_length (config);
910 for (i = 0; i < t; i++)
912 struct config_section_s *s = slist_nth_data (config, i);
914 if (!strcmp (s->name, name))
915 return s;
918 return NULL;
921 /* Append a new parameter to the list of parameters for a file
922 * section. When an existing parameter of the same name exists, its
923 * value is updated.
925 static int
926 new_param (struct config_section_s *section, const char *filename, int lineno,
927 const char *name, const char *value, int type)
929 struct config_param_s *param = NULL;
930 struct slist_s *tmp;
931 char *e;
932 unsigned i, t = slist_length (section->params);
933 int dup = 0;
935 for (i = 0; i < t; i++)
937 struct config_param_s *p = slist_nth_data (section->params, i);
938 if (!p)
939 break;
941 if (!strcmp (name, p->name))
943 param = p;
944 dup = 1;
945 break;
949 if (!param)
951 param = xcalloc (1, sizeof (struct config_param_s));
952 if (!param)
954 log_write ("%s", pwmd_strerror (ENOMEM));
955 return 1;
958 param->name = str_dup (name);
959 if (!param->name)
961 xfree (param);
962 log_write ("%s", pwmd_strerror (ENOMEM));
963 return 1;
967 param->type = type;
969 switch (type)
971 case PARAM_BOOL:
972 if (!strcasecmp (value, "no") || !strcasecmp (value, "0")
973 || !strcasecmp (value, "false"))
974 param->value.itype = 0;
975 else if (!strcasecmp (value, "yes") || !strcasecmp (value, "1")
976 || !strcasecmp (value, "true"))
977 param->value.itype = 1;
978 else
980 INVALID_VALUE (filename, lineno);
981 goto fail;
983 param->type = PARAM_INT;
984 break;
985 case PARAM_CHARP:
986 xfree (param->value.cptype);
987 param->value.cptype = NULL;
988 param->value.cptype = value && *value ? str_dup (value) : NULL;
989 if (value && *value && !param->value.cptype)
991 log_write ("%s", pwmd_strerror (ENOMEM));
992 goto fail;
994 break;
995 case PARAM_CHARPP:
996 strv_free (param->value.cpptype);
997 param->value.cpptype = NULL;
998 param->value.cpptype = value && *value ? str_split (value, ",", 0) : NULL;
999 if (value && *value && !param->value.cpptype)
1001 log_write ("%s", pwmd_strerror (ENOMEM));
1002 goto fail;
1004 break;
1005 case PARAM_INT:
1006 param->value.itype = strtol (value, &e, 10);
1007 if (e && *e)
1009 INVALID_VALUE (filename, lineno);
1010 goto fail;
1012 break;
1013 case PARAM_LONG:
1014 param->value.ltype = strtol (value, &e, 10);
1015 if (e && *e)
1017 INVALID_VALUE (filename, lineno);
1018 goto fail;
1020 break;
1021 case PARAM_LONGLONG:
1022 param->value.lltype = strtoll (value, &e, 10);
1023 if (e && *e)
1025 INVALID_VALUE (filename, lineno);
1026 goto fail;
1028 break;
1029 case PARAM_ULONGLONG:
1030 param->value.ulltype = strtoull (value, &e, 10);
1031 if (e && *e)
1033 INVALID_VALUE (filename, lineno);
1034 goto fail;
1036 break;
1037 case PARAM_ULONG:
1038 param->value.ultype = strtoul (value, &e, 10);
1039 if (e && *e)
1041 INVALID_VALUE (filename, lineno);
1042 goto fail;
1044 break;
1047 if (dup)
1048 return 0;
1050 tmp = slist_append (section->params, param);
1051 if (!tmp)
1053 log_write ("%s", pwmd_strerror (ENOMEM));
1054 goto fail;
1057 section->params = tmp;
1058 return 0;
1060 fail:
1061 xfree (param->name);
1062 xfree (param);
1063 return 1;
1066 struct slist_s *
1067 config_parse (const char *filename)
1069 struct slist_s *tmpconfig = NULL, *tmp;
1070 struct config_section_s *cur_section = NULL;
1071 char buf[LINE_MAX];
1072 char *s;
1073 int lineno = 1;
1074 int have_global = 0;
1075 FILE *fp = fopen (filename, "r");
1077 if (!fp)
1079 log_write ("%s: %s", filename,
1080 pwmd_strerror (gpg_error_from_errno (errno)));
1082 if (errno != ENOENT)
1083 return NULL;
1085 log_write (_("Using defaults!"));
1086 goto defaults;
1089 for (; (s = fgets (buf, sizeof (buf), fp)); lineno++)
1091 char line[LINE_MAX] = { 0 };
1092 size_t len = 0;
1094 if (*s == '#')
1095 continue;
1097 s = str_chomp (s);
1098 for (; s && *s; s++)
1100 int match = 0;
1102 /* New file section. */
1103 if (*s == '[')
1105 struct config_section_s *section;
1106 char *p = strchr (++s, ']');
1108 if (!p)
1110 log_write (_("%s(%i): unbalanced braces"), filename,
1111 lineno);
1112 goto fail;
1115 len = strlen (s) - strlen (p);
1116 memcpy (line, s, len);
1117 line[len] = 0;
1119 section = config_find_section (tmpconfig, line);
1120 if (section)
1122 log_write (_("%s(%i): section '%s' already exists!"),
1123 filename, lineno, line);
1124 goto fail;
1127 if (!strcmp (line, "global"))
1128 have_global = 1;
1130 section = xcalloc (1, sizeof (struct config_section_s));
1131 section->name = str_dup (line);
1133 if (cur_section)
1135 tmp = slist_append (tmpconfig, cur_section);
1136 if (!tmp)
1138 log_write ("%s", pwmd_strerror (ENOMEM));
1139 goto fail;
1142 tmpconfig = tmp;
1145 cur_section = section;
1146 break;
1149 if (!cur_section)
1151 log_write (_("%s(%i): parameter outside of section!"), filename,
1152 lineno);
1153 goto fail;
1156 /* Parameters for each section. */
1157 for (int m = 0; config_params[m].name; m++)
1159 size_t len = strlen (config_params[m].name);
1161 if (!strncmp (s, config_params[m].name, len))
1163 char *p = s + len;
1165 while (*p && *p == ' ')
1166 p++;
1168 if (!*p || *p != '=')
1169 continue;
1171 p++;
1172 while (*p && isspace (*p))
1173 p++;
1175 s[len] = 0;
1176 if (new_param (cur_section, filename, lineno, s, p,
1177 config_params[m].type))
1178 goto fail;
1180 match = 1;
1181 break;
1185 if (!match)
1187 log_write (_("%s(%i): unknown parameter"), filename, lineno);
1188 goto fail;
1191 break;
1195 if (cur_section)
1197 tmp = slist_append (tmpconfig, cur_section);
1198 if (!tmp)
1200 log_write ("%s", pwmd_strerror (ENOMEM));
1201 goto fail;
1204 cur_section = NULL;
1205 tmpconfig = tmp;
1208 if (!have_global)
1209 log_write (_
1210 ("WARNING: %s: could not find a [global] configuration section!"),
1211 filename);
1213 defaults:
1214 if (set_defaults (&tmpconfig))
1215 goto fail;
1217 if (fp)
1218 fclose(fp);
1220 return tmpconfig;
1222 fail:
1223 if (fp)
1224 fclose (fp);
1226 config_free (tmpconfig);
1227 free_section (cur_section);
1228 return NULL;
1231 static void
1232 free_section (struct config_section_s *s)
1234 if (!s)
1235 return;
1237 for (;;)
1239 struct config_param_s *p = slist_nth_data (s->params, 0);
1241 if (!p)
1242 break;
1244 section_remove_param (s, p->name);
1247 s->params = NULL;
1248 xfree (s->name);
1249 s->name = NULL;
1252 void
1253 config_free (struct slist_s *config)
1255 for (;;)
1257 struct config_section_s *s = slist_nth_data (config, 0);
1258 if (!s)
1259 break;
1261 free_section (s);
1262 config = slist_remove (config, s);
1263 xfree (s);