Fix Coverity issue #100360.
[libpwmd.git] / src / rcfile.c
blob843570b6fbd1469beb16a5c3a7fa4c230ea3ffcb
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015
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 <gcrypt.h>
35 #include "mutex.h"
36 #include "rcfile.h"
37 #include "util-misc.h"
38 #include "common.h"
39 #include "util-slist.h"
40 #include "util-string.h"
41 #include "mem.h"
43 #define DEFAULT_PINENTRY_TIMEOUT "30"
44 #define DEFAULT_CACHE_TIMEOUT "600"
45 #define DEFAULT_KEEPALIVE_INTERVAL "60"
46 #define DEFAULT_LOCK_TIMEOUT "50" // MUTEX_TRYLOCK in tenths of a second
48 #define INVALID_VALUE(file, line) do { \
49 if (file) \
50 log_write(_("%s(%i): invalid value for parameter."), file, line); \
51 } while (0);
53 enum
55 PARAM_INT, PARAM_CHARP, PARAM_LONG, PARAM_LONGLONG, PARAM_CHARPP,
56 PARAM_BOOL, PARAM_ULONG, PARAM_ULONGLONG
59 static struct config_params_s
61 char *name;
62 int type;
63 char *value;
64 } config_params[] = {
65 { "backup", PARAM_BOOL, "true"},
66 { "socket_path", PARAM_CHARP, NULL},
67 { "socket_perms", PARAM_CHARP, NULL},
68 { "passphrase", PARAM_CHARP, NULL},
69 { "passphrase_file", PARAM_CHARP, NULL},
70 { "gpg_agent_socket", PARAM_CHARP, NULL},
71 { "log_path", PARAM_CHARP, "~/.pwmd/log"},
72 { "enable_logging", PARAM_BOOL, "0"},
73 { "log_keepopen", PARAM_BOOL, "true"},
74 { "log_level", PARAM_INT, "0"},
75 { "disable_mlockall", PARAM_BOOL, "true"},
76 { "cache_timeout", PARAM_INT, DEFAULT_CACHE_TIMEOUT},
77 { "cache_push", PARAM_CHARPP, NULL},
78 { "disable_list_and_dump", PARAM_BOOL, "false"},
79 { "recursion_depth", PARAM_INT, "100"},
80 { "syslog", PARAM_BOOL, "false"},
81 { "xfer_progress", PARAM_INT, "8196"},
82 { "allowed", PARAM_CHARPP, NULL},
83 { "allowed_file", PARAM_CHARP, NULL},
84 { "keyparam", PARAM_CHARP, "(genkey (rsa (nbits 4:2048)))"},
85 { "cipher", PARAM_CHARP, "aes256"},
86 { "kill_scd", PARAM_BOOL, "false"},
87 { "cipher_iterations", PARAM_ULONGLONG, "0"},
88 { "cipher_progress", PARAM_LONG, DEFAULT_ITERATION_PROGRESS},
89 { "priority", PARAM_INT, INVALID_PRIORITY},
90 { "keepalive_interval", PARAM_INT, DEFAULT_KEEPALIVE_INTERVAL},
91 { "tcp_port", PARAM_INT, "6466"},
92 { "enable_tcp", PARAM_BOOL, "false"},
93 { "tcp_require_key", PARAM_BOOL, "false"},
94 { "tcp_wait", PARAM_INT, "0"},
95 { "tcp_bind", PARAM_CHARP, "any"},
96 { "tcp_interface", PARAM_CHARP, NULL},
97 { "tls_timeout", PARAM_INT, "300"},
98 { "tls_cipher_suite", PARAM_CHARP, "SECURE256"},
99 { "pinentry_path", PARAM_CHARP, PINENTRY_PATH},
100 { "pinentry_timeout", PARAM_INT, DEFAULT_PINENTRY_TIMEOUT},
101 { "use_agent", PARAM_BOOL, "false"},
102 { "require_save_key", PARAM_BOOL, "true"},
103 { "invoking_user", PARAM_CHARP, NULL},
104 { "invoking_tls", PARAM_CHARP, NULL},
105 { "lock_timeout", PARAM_INT, DEFAULT_LOCK_TIMEOUT},
106 { "send_state", PARAM_INT, "2"},
107 { NULL, 0, NULL},
110 struct config_param_s
112 char *name;
113 int type;
114 union
116 int itype;
117 char *cptype;
118 char **cpptype;
119 long ltype;
120 long long lltype;
121 unsigned long ultype;
122 unsigned long long ulltype;
123 } value;
126 static struct config_section_s *config_find_section (struct slist_s *config,
127 const char *name);
128 static int new_param (struct config_section_s *section, const char *filename,
129 int lineno, const char *name, const char *value,
130 int type);
131 static void free_section (struct config_section_s *s);
132 static int set_defaults (struct slist_s **config);
134 static void
135 section_remove_param (struct config_section_s *section, const char *name)
137 unsigned i, t = slist_length (section->params);
139 for (i = 0; i < t; i++)
141 struct config_param_s *p = slist_nth_data (section->params, i);
143 if (!p)
144 continue;
146 if (!strcmp (p->name, name))
148 switch (p->type)
150 case PARAM_CHARP:
151 xfree (p->value.cptype);
152 break;
153 case PARAM_CHARPP:
154 strv_free (p->value.cpptype);
155 break;
158 section->params = slist_remove (section->params, p);
159 xfree (p->name);
160 xfree (p);
161 break;
166 void
167 config_clear_keys ()
169 MUTEX_LOCK (&rcfile_mutex);
170 unsigned i, t = slist_length (global_config);
172 for (i = 0; i < t; i++)
174 struct config_section_s *s = slist_nth_data (global_config, i);
175 if (!s)
176 continue;
178 section_remove_param (s, "passphrase");
181 MUTEX_UNLOCK (&rcfile_mutex);
184 static struct config_param_s *
185 config_has_param (struct config_section_s *s, const char *what)
187 unsigned i, t = slist_length (s->params);
189 for (i = 0; i < t; i++)
191 struct config_param_s *p = slist_nth_data (s->params, i);
192 if (!p)
193 break;
195 if (!strcmp (p->name, what))
196 return p;
199 return NULL;
202 static struct config_param_s *
203 config_get_param (struct slist_s *config,
204 const char *section, const char *what, int *exists)
206 unsigned i, t = slist_length (config);
208 *exists = 0;
210 for (i = 0; i < t; i++)
212 struct config_param_s *p;
213 struct config_section_s *s = slist_nth_data (config, i);
215 if (!s)
216 break;
218 if (strcmp (s->name, section))
219 continue;
221 p = config_has_param (s, what);
222 if (!p)
223 return NULL;
225 *exists = 1;
226 return p;
229 return NULL;
232 static struct config_section_s *
233 new_section (struct slist_s **config, const char *name)
235 struct slist_s *tmp;
236 struct config_section_s *s = xcalloc (1, sizeof (struct config_section_s));
238 if (!s)
239 return NULL;
241 s->name = str_dup (name);
242 if (!s->name)
244 log_write ("%s", pwmd_strerror (ENOMEM));
245 xfree (s);
246 return NULL;
249 tmp = slist_append (*config, s);
250 if (!tmp)
252 log_write ("%s", pwmd_strerror (ENOMEM));
253 xfree (s->name);
254 xfree (s);
255 return NULL;
258 *config = tmp;
259 return s;
263 config_set_string_param (struct slist_s **config, const char *section,
264 const char *name, const char *value)
266 struct config_section_s *s = config_find_section (*config, section);
268 if (!s)
270 s = new_section (config, section);
271 if (!s)
272 return 1;
275 return new_param (s, NULL, 0, name, value, PARAM_CHARP);
278 char *
279 config_get_string_param (struct slist_s *config, const char *section,
280 const char *what, int *exists)
282 struct config_param_s *p = config_get_param (config, section, what, exists);
283 return *exists && p->value.cptype ? str_dup (p->value.cptype) : NULL;
287 config_set_int_param (struct slist_s **config, const char *section,
288 const char *name, const char *value)
290 struct config_section_s *s = config_find_section (*config, section);
292 if (!s)
294 s = new_section (config, section);
295 if (!s)
296 return 1;
299 return new_param (s, NULL, 0, name, value, PARAM_INT);
303 config_get_int_param (struct slist_s *config, const char *section,
304 const char *what, int *exists)
306 struct config_param_s *p = config_get_param (config, section, what, exists);
307 return *exists ? p->value.itype : -1;
311 config_set_bool_param (struct slist_s **config, const char *section,
312 const char *name, const char *value)
314 struct config_section_s *s = config_find_section (*config, section);
316 if (!s)
318 s = new_section (config, section);
319 if (!s)
320 return 1;
323 return new_param (s, NULL, 0, name, value, PARAM_BOOL);
327 config_get_bool_param (struct slist_s *config, const char *section,
328 const char *what, int *exists)
330 return config_get_int_param (config, section, what, exists);
334 config_set_long_param (struct slist_s **config, const char *section,
335 const char *name, const char *value)
337 struct config_section_s *s = config_find_section (*config, section);
339 if (!s)
341 s = new_section (config, section);
342 if (!s)
343 return 1;
346 return new_param (s, NULL, 0, name, value, PARAM_LONG);
349 unsigned long
350 config_get_ulong_param (struct slist_s *config, const char *section,
351 const char *what, int *exists)
353 struct config_param_s *p = config_get_param (config, section, what, exists);
354 return *exists ? p->value.ultype : 0;
357 long
358 config_get_long_param (struct slist_s *config, const char *section,
359 const char *what, int *exists)
361 struct config_param_s *p = config_get_param (config, section, what, exists);
362 return *exists ? p->value.ltype : -1;
366 config_set_longlong_param (struct slist_s **config, const char *section,
367 const char *name, const char *value)
369 struct config_section_s *s = config_find_section (*config, section);
371 if (!s)
373 s = new_section (config, section);
374 if (!s)
375 return 1;
378 return new_param (s, NULL, 0, name, value, PARAM_LONGLONG);
381 long long
382 config_get_longlong_param (struct slist_s *config,
383 const char *section, const char *what, int *exists)
385 struct config_param_s *p = config_get_param (config, section, what, exists);
386 return *exists ? p->value.lltype : -1;
389 unsigned long long
390 config_get_ulonglong_param (struct slist_s *config,
391 const char *section,
392 const char *what, int *exists)
394 struct config_param_s *p = config_get_param (config, section, what, exists);
395 return *exists ? p->value.ulltype : 0;
399 config_set_list_param (struct slist_s **config, const char *section,
400 const char *name, const char *value)
402 struct config_section_s *s = config_find_section (*config, section);
404 if (!s)
406 s = new_section (config, section);
407 if (!s)
408 return 1;
411 return new_param (s, NULL, 0, name, value, PARAM_CHARPP);
414 char **
415 config_get_list_param (struct slist_s *config, const char *section,
416 const char *what, int *exists)
418 struct config_param_s *p = config_get_param (config, section, what, exists);
419 return *exists && p->value.cpptype ? strv_dup (p->value.cpptype) : NULL;
422 char *
423 config_get_string (const char *section, const char *what)
425 char *val = NULL;
426 const char *where = section ? section : "global";
427 int exists = 0;
429 MUTEX_LOCK (&rcfile_mutex);
430 val = config_get_string_param (global_config, where, what, &exists);
431 if (!exists && strcmp (section ? section : "", "global"))
432 val = config_get_string_param (global_config, "global", what, &exists);
434 MUTEX_UNLOCK (&rcfile_mutex);
435 return val;
438 char **
439 config_get_list (const char *section, const char *what)
441 char **val = NULL;
442 const char *where = section ? section : "global";
443 int exists = 0;
445 MUTEX_LOCK (&rcfile_mutex);
446 val = config_get_list_param (global_config, where, what, &exists);
447 if (!exists && strcmp (section ? section : "", "global"))
448 val = config_get_list_param (global_config, "global", what, &exists);
450 MUTEX_UNLOCK (&rcfile_mutex);
451 return val;
455 config_get_integer (const char *section, const char *what)
457 int val = 0;
458 const char *where = section ? section : "global";
459 int exists = 0;
461 MUTEX_LOCK (&rcfile_mutex);
462 val = config_get_int_param (global_config, where, what, &exists);
463 if (!exists && strcmp (section ? section : "", "global"))
464 val = config_get_int_param (global_config, "global", what, &exists);
466 MUTEX_UNLOCK (&rcfile_mutex);
467 return val;
470 long long
471 config_get_longlong (const char *section, const char *what)
473 long long val = 0;
474 const char *where = section ? section : "global";
475 int exists = 0;
477 MUTEX_LOCK (&rcfile_mutex);
478 val = config_get_longlong_param (global_config, where, what, &exists);
479 if (!exists && strcmp (section ? section : "", "global"))
480 val = config_get_longlong_param (global_config, "global", what, &exists);
482 MUTEX_UNLOCK (&rcfile_mutex);
483 return val;
486 unsigned long long
487 config_get_ulonglong (const char *section, const char *what)
489 unsigned long long val = 0;
490 const char *where = section ? section : "global";
491 int exists = 0;
493 MUTEX_LOCK (&rcfile_mutex);
494 val = config_get_ulonglong_param (global_config, where, what, &exists);
495 if (!exists && strcmp (section ? section : "", "global"))
496 val = config_get_ulonglong_param (global_config, "global", what, &exists);
498 MUTEX_UNLOCK (&rcfile_mutex);
499 return val;
502 long
503 config_get_long (const char *section, const char *what)
505 long val = 0;
506 const char *where = section ? section : "global";
507 int exists = 0;
509 MUTEX_LOCK (&rcfile_mutex);
510 val = config_get_long_param (global_config, where, what, &exists);
511 if (!exists && strcmp (section ? section : "", "global"))
512 val = config_get_long_param (global_config, "global", what, &exists);
514 MUTEX_UNLOCK (&rcfile_mutex);
515 return val;
518 unsigned long
519 config_get_ulong (const char *section, const char *what)
521 unsigned long val = 0;
522 const char *where = section ? section : "global";
523 int exists = 0;
525 MUTEX_LOCK (&rcfile_mutex);
526 val = config_get_ulong_param (global_config, where, what, &exists);
527 if (!exists && strcmp (section ? section : "", "global"))
528 val = config_get_ulong_param (global_config, "global", what, &exists);
530 MUTEX_UNLOCK (&rcfile_mutex);
531 return val;
535 config_get_boolean (const char *section, const char *what)
537 return config_get_integer (section, what);
540 char *
541 config_get_value (const char *section, const char *what)
543 const char *where = section ? section : "global";
544 int exists = 0;
545 int i;
546 int ival;
547 long lval;
548 long long llval;
549 unsigned long ulval;
550 unsigned long long ullval;
551 char *cpval;
552 char **cppval;
553 char *result = NULL;
555 MUTEX_LOCK (&rcfile_mutex);
557 for (i = 0; config_params[i].name; i++)
559 if (!strcmp (config_params[i].name, what))
561 switch (config_params[i].type)
563 case PARAM_BOOL:
564 case PARAM_INT:
565 ival = config_get_int_param (global_config, where, what,
566 &exists);
567 if (!exists && strcmp (section ? section : "", "global"))
568 ival = config_get_int_param (global_config, "global", what,
569 &exists);
570 result = str_asprintf ("%i", ival);
571 break;
572 case PARAM_CHARP:
573 cpval = config_get_string_param (global_config, where, what,
574 &exists);
575 if (!exists && strcmp (section ? section : "", "global"))
576 cpval =
577 config_get_string_param (global_config, "global", what,
578 &exists);
579 result = cpval;
580 break;
581 case PARAM_LONG:
582 lval = config_get_long_param (global_config, where, what,
583 &exists);
584 if (!exists && strcmp (section ? section : "", "global"))
585 lval = config_get_long_param (global_config, "global", what,
586 &exists);
587 result = str_asprintf ("%li", lval);
588 break;
589 case PARAM_ULONG:
590 ulval = config_get_ulong_param (global_config, where, what,
591 &exists);
592 if (!exists && strcmp (section ? section : "", "global"))
593 ulval = config_get_ulong_param (global_config, "global", what,
594 &exists);
595 result = str_asprintf ("%lu", ulval);
596 break;
597 case PARAM_LONGLONG:
598 llval = config_get_longlong_param (global_config, where, what,
599 &exists);
600 if (!exists && strcmp (section ? section : "", "global"))
601 llval = config_get_longlong_param (global_config, "global",
602 what, &exists);
603 result = str_asprintf ("%lli", llval);
604 break;
605 case PARAM_ULONGLONG:
606 ullval = config_get_ulonglong_param (global_config, where, what,
607 &exists);
608 if (!exists && strcmp (section ? section : "", "global"))
609 ullval = config_get_ulonglong_param (global_config, "global",
610 what, &exists);
611 result = str_asprintf ("%llu", ullval);
612 break;
613 case PARAM_CHARPP:
614 cppval = config_get_list_param (global_config, where, what,
615 &exists);
616 if (!exists && strcmp (section ? section : "", "global"))
617 cppval = config_get_list_param (global_config, "global", what,
618 &exists);
620 if (cppval)
621 result = strv_join (",", cppval);
623 strv_free (cppval);
624 break;
629 MUTEX_UNLOCK (&rcfile_mutex);
630 return result;
633 static void
634 parse_allowed_file (struct slist_s *config, const char *section)
636 FILE *fp;
637 char buf[LINE_MAX];
638 int exists;
639 char **list = NULL;
640 char *tmp;
641 char *p = config_get_string_param (config, section, "allowed_file", &exists);
643 if (!p || !*p)
645 xfree (p);
646 return;
649 tmp = expand_homedir (p);
650 xfree (p);
651 p = tmp;
652 fp = fopen (p, "r");
653 if (!fp)
655 log_write ("%s: %s", p, strerror (errno));
656 xfree (p);
657 return;
660 xfree (p);
661 list = config_get_list_param (config, section, "allowed", &exists);
662 if (!list && exists)
664 fclose (fp);
665 log_write ("%s", strerror (ENOMEM));
666 return;
669 while ((p = fgets (buf, sizeof (buf), fp)))
671 char **pp = NULL;
673 if (p[strlen(p)-1] == '\n')
674 p[strlen(p)-1] = 0;
676 while (*p && isspace (*p))
677 p++;
679 if (!*p)
680 continue;
682 tmp = str_dup (p);
683 if (tmp)
684 pp = strv_cat (list, str_dup (p));
686 if (!pp || !tmp)
688 xfree (tmp);
689 strv_free (list);
690 fclose (fp);
691 log_write ("%s", strerror (ENOMEM));
692 return;
695 xfree (tmp);
696 list = pp;
699 fclose(fp);
700 if (!list)
701 return;
703 p = strv_join (",", list);
704 strv_free (list);
706 if (!p)
708 log_write ("%s", strerror (ENOMEM));
709 return;
712 config_set_list_param (&config, section, "allowed", p);
713 xfree (p);
716 static int
717 fixup_allowed_once (struct slist_s **config, const char *section)
719 char **list, **pp, *p;
720 int exists;
722 parse_allowed_file (*config, section);
723 list = config_get_list_param (*config, section, "allowed", &exists);
724 for (pp = list; pp && *pp; pp++)
726 if (*(*pp) == '#')
728 for (p = *pp; p && *p; p++)
729 *p = toupper(*p);
733 strv_free (list);
734 if (!exists)
736 if (!strcmp (section, "global"))
738 p = get_username (getuid());
740 if (config_set_list_param (config, section, "allowed", p))
742 xfree (p);
743 return 1;
746 xfree (p);
748 else
750 list = config_get_list_param (*config, "global", "allowed", &exists);
751 if (list)
753 p = strv_join (",", list);
754 strv_free (list);
755 if (config_set_list_param (config, section, "allowed", p))
757 xfree (p);
758 return 1;
761 xfree (p);
766 return 0;
769 static int
770 fixup_allowed (struct slist_s **config)
772 int n, t = slist_length (*config);
774 for (n = 0; n < t; n++)
776 struct config_section_s *section;
778 section = slist_nth_data (*config, n);
779 if (fixup_allowed_once (config, section->name))
780 return 1;
783 return 0;
786 static int
787 set_defaults (struct slist_s **config)
789 char *s = NULL, *tmp;
790 char **list;
791 int exists;
792 int i;
793 struct passwd *pwd;
795 for (i = 0; config_params[i].name; i++)
797 switch (config_params[i].type)
799 case PARAM_BOOL:
800 config_get_bool_param (*config, "global", config_params[i].name,
801 &exists);
802 if (!exists)
804 if (config_set_bool_param
805 (config, "global", config_params[i].name,
806 config_params[i].value))
807 goto fail;
809 break;
810 case PARAM_INT:
811 config_get_int_param (*config, "global", config_params[i].name,
812 &exists);
813 if (!exists)
815 if (config_set_int_param
816 (config, "global", config_params[i].name,
817 config_params[i].value))
818 goto fail;
820 break;
821 case PARAM_CHARP:
822 s = config_get_string_param (*config, "global",
823 config_params[i].name, &exists);
824 xfree (s);
825 if (!exists && config_params[i].value)
827 if (config_set_string_param (config, "global",
828 config_params[i].name,
829 config_params[i].value))
830 goto fail;
832 break;
833 case PARAM_CHARPP:
834 list = config_get_list_param (*config, "global",
835 config_params[i].name, &exists);
836 strv_free (list);
837 if (!exists && config_params[i].value)
839 if (config_set_list_param (config, "global",
840 config_params[i].name,
841 config_params[i].value))
842 goto fail;
844 break;
845 case PARAM_LONG:
846 config_get_long_param (*config, "global", config_params[i].name,
847 &exists);
848 if (!exists)
850 if (config_set_long_param
851 (config, "global", config_params[i].name,
852 config_params[i].value))
853 goto fail;
855 break;
856 case PARAM_LONGLONG:
857 config_get_longlong_param (*config, "global", config_params[i].name,
858 &exists);
859 if (!exists)
861 if (config_set_longlong_param (config, "global",
862 config_params[i].name,
863 config_params[i].value))
864 goto fail;
866 break;
870 s = NULL;
871 if (fixup_allowed (config))
872 goto fail;
874 max_recursion_depth = config_get_int_param (*config, "global",
875 "recursion_depth", &exists);
876 disable_list_and_dump = config_get_bool_param (*config, "global",
877 "disable_list_and_dump",
878 &exists);
879 #ifdef HAVE_MLOCKALL
880 disable_mlock =
881 config_get_bool_param (*config, "global", "disable_mlockall", &exists);
882 #endif
884 s = config_get_string_param(*config, "global", "invoking_user", &exists);
885 errno = 0;
886 if (!s || !*s)
887 pwd = getpwuid(getuid());
888 else
889 pwd = getpwnam(s);
891 if (!pwd)
893 log_write (_("could not set invoking user: user '%s' is invalid"), s);
894 goto fail;
897 xfree (s);
898 config_set_string_param(config, "global", "invoking_user", pwd->pw_name);
899 #ifdef WITH_GNUTLS
900 invoking_tls = config_get_string_param(*config, "global", "invoking_tls",
901 &exists);
902 for (char *p = invoking_tls; p && *p; p++)
903 *p = toupper(*p);
905 config_set_string_param(config, "global", "invoking_tls", invoking_tls);
906 #endif
907 invoking_uid = pwd->pw_uid;
908 invoking_gid = pwd->pw_gid;
910 s = config_get_string_param(*config, "global", "gpg_agent_socket", &exists);
911 if (!s || !*s)
913 xfree (s);
914 s = str_asprintf ("%s/.gnupg/S.gpg-agent", get_home_dir());
915 config_set_string_param(config, "global", "gpg_agent_socket", s);
917 else
919 tmp = expand_homedir (s);
920 config_set_string_param(config, "global", "gpg_agent_socket", tmp);
921 xfree (tmp);
924 xfree (s);
925 return 0;
927 fail:
928 xfree (s);
929 return 1;
932 static struct config_section_s *
933 config_find_section (struct slist_s *config, const char *name)
935 unsigned i, t = slist_length (config);
937 for (i = 0; i < t; i++)
939 struct config_section_s *s = slist_nth_data (config, i);
941 if (!strcmp (s->name, name))
942 return s;
945 return NULL;
948 /* Append a new parameter to the list of parameters for a file
949 * section. When an existing parameter of the same name exists, its
950 * value is updated.
952 static int
953 new_param (struct config_section_s *section, const char *filename, int lineno,
954 const char *name, const char *value, int type)
956 struct config_param_s *param = NULL;
957 struct slist_s *tmp;
958 char *e;
959 unsigned i, t = slist_length (section->params);
960 int dup = 0;
962 for (i = 0; i < t; i++)
964 struct config_param_s *p = slist_nth_data (section->params, i);
965 if (!p)
966 break;
968 if (!strcmp (name, p->name))
970 param = p;
971 dup = 1;
972 break;
976 if (!param)
978 param = xcalloc (1, sizeof (struct config_param_s));
979 if (!param)
981 log_write ("%s", pwmd_strerror (ENOMEM));
982 return 1;
985 param->name = str_dup (name);
986 if (!param->name)
988 xfree (param);
989 log_write ("%s", pwmd_strerror (ENOMEM));
990 return 1;
994 param->type = type;
996 switch (type)
998 case PARAM_BOOL:
999 if (!strcasecmp (value, "no") || !strcasecmp (value, "0")
1000 || !strcasecmp (value, "false"))
1001 param->value.itype = 0;
1002 else if (!strcasecmp (value, "yes") || !strcasecmp (value, "1")
1003 || !strcasecmp (value, "true"))
1004 param->value.itype = 1;
1005 else
1007 INVALID_VALUE (filename, lineno);
1008 goto fail;
1010 param->type = PARAM_INT;
1011 break;
1012 case PARAM_CHARP:
1013 xfree (param->value.cptype);
1014 param->value.cptype = NULL;
1015 param->value.cptype = value && *value ? str_dup (value) : NULL;
1016 if (value && *value && !param->value.cptype)
1018 log_write ("%s", pwmd_strerror (ENOMEM));
1019 goto fail;
1021 break;
1022 case PARAM_CHARPP:
1023 strv_free (param->value.cpptype);
1024 param->value.cpptype = NULL;
1025 param->value.cpptype = value && *value ? str_split (value, ",", 0) : NULL;
1026 if (value && *value && !param->value.cpptype)
1028 log_write ("%s", pwmd_strerror (ENOMEM));
1029 goto fail;
1031 break;
1032 case PARAM_INT:
1033 param->value.itype = strtol (value, &e, 10);
1034 if (e && *e)
1036 INVALID_VALUE (filename, lineno);
1037 goto fail;
1039 break;
1040 case PARAM_LONG:
1041 param->value.ltype = strtol (value, &e, 10);
1042 if (e && *e)
1044 INVALID_VALUE (filename, lineno);
1045 goto fail;
1047 break;
1048 case PARAM_LONGLONG:
1049 param->value.lltype = strtoll (value, &e, 10);
1050 if (e && *e)
1052 INVALID_VALUE (filename, lineno);
1053 goto fail;
1055 break;
1056 case PARAM_ULONGLONG:
1057 param->value.ulltype = strtoull (value, &e, 10);
1058 if (e && *e)
1060 INVALID_VALUE (filename, lineno);
1061 goto fail;
1063 break;
1064 case PARAM_ULONG:
1065 param->value.ultype = strtoul (value, &e, 10);
1066 if (e && *e)
1068 INVALID_VALUE (filename, lineno);
1069 goto fail;
1071 break;
1074 if (dup)
1075 return 0;
1077 tmp = slist_append (section->params, param);
1078 if (!tmp)
1080 log_write ("%s", pwmd_strerror (ENOMEM));
1081 goto fail;
1084 section->params = tmp;
1085 return 0;
1087 fail:
1088 xfree (param->name);
1089 xfree (param);
1090 return 1;
1093 struct slist_s *
1094 config_parse (const char *filename)
1096 struct slist_s *tmpconfig = NULL, *tmp;
1097 struct config_section_s *cur_section = NULL;
1098 char buf[LINE_MAX];
1099 char *s;
1100 int lineno = 1;
1101 int have_global = 0;
1102 FILE *fp = fopen (filename, "r");
1104 if (!fp)
1106 log_write ("%s: %s", filename,
1107 pwmd_strerror (gpg_error_from_errno (errno)));
1109 if (errno != ENOENT)
1110 return NULL;
1112 log_write (_("Using defaults!"));
1113 goto defaults;
1116 for (; (s = fgets (buf, sizeof (buf), fp)); lineno++)
1118 char line[LINE_MAX] = { 0 };
1119 size_t len = 0;
1121 if (*s == '#')
1122 continue;
1124 s = str_chomp (s);
1125 for (; s && *s; s++)
1127 int match = 0;
1129 /* New file section. */
1130 if (*s == '[')
1132 struct config_section_s *section;
1133 char *p = strchr (++s, ']');
1135 if (!p)
1137 log_write (_("%s(%i): unbalanced braces"), filename,
1138 lineno);
1139 goto fail;
1142 len = strlen (s) - strlen (p);
1143 memcpy (line, s, len);
1144 line[len] = 0;
1146 section = config_find_section (tmpconfig, line);
1147 if (section)
1149 log_write (_("%s(%i): section '%s' already exists!"),
1150 filename, lineno, line);
1151 goto fail;
1154 if (!strcmp (line, "global"))
1155 have_global = 1;
1157 section = xcalloc (1, sizeof (struct config_section_s));
1158 section->name = str_dup (line);
1160 if (cur_section)
1162 tmp = slist_append (tmpconfig, cur_section);
1163 if (!tmp)
1165 log_write ("%s", pwmd_strerror (ENOMEM));
1166 goto fail;
1169 tmpconfig = tmp;
1172 cur_section = section;
1173 break;
1176 if (!cur_section)
1178 log_write (_("%s(%i): parameter outside of section!"), filename,
1179 lineno);
1180 goto fail;
1183 /* Parameters for each section. */
1184 for (int m = 0; config_params[m].name; m++)
1186 size_t len = strlen (config_params[m].name);
1188 if (!strncmp (s, config_params[m].name, len))
1190 char *p = s + len;
1192 while (*p && *p == ' ')
1193 p++;
1195 if (!*p || *p != '=')
1196 continue;
1198 p++;
1199 while (*p && isspace (*p))
1200 p++;
1202 s[len] = 0;
1203 if (new_param (cur_section, filename, lineno, s, p,
1204 config_params[m].type))
1205 goto fail;
1207 match = 1;
1208 break;
1212 if (!match)
1214 log_write (_("%s(%i): unknown parameter"), filename, lineno);
1215 goto fail;
1218 break;
1222 if (cur_section)
1224 tmp = slist_append (tmpconfig, cur_section);
1225 if (!tmp)
1227 log_write ("%s", pwmd_strerror (ENOMEM));
1228 goto fail;
1231 cur_section = NULL;
1232 tmpconfig = tmp;
1235 if (!have_global)
1236 log_write (_
1237 ("WARNING: %s: could not find a [global] configuration section!"),
1238 filename);
1240 defaults:
1241 if (set_defaults (&tmpconfig))
1242 goto fail;
1244 if (fp)
1245 fclose(fp);
1247 return tmpconfig;
1249 fail:
1250 if (fp)
1251 fclose (fp);
1253 config_free (tmpconfig);
1254 free_section (cur_section);
1255 return NULL;
1258 static void
1259 free_section (struct config_section_s *s)
1261 if (!s)
1262 return;
1264 for (;;)
1266 struct config_param_s *p = slist_nth_data (s->params, 0);
1268 if (!p)
1269 break;
1271 section_remove_param (s, p->name);
1274 s->params = NULL;
1275 xfree (s->name);
1276 s->name = NULL;
1279 void
1280 config_free (struct slist_s *config)
1282 for (;;)
1284 struct config_section_s *s = slist_nth_data (config, 0);
1285 if (!s)
1286 break;
1288 free_section (s);
1289 config = slist_remove (config, s);
1290 xfree (s);