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/>.
26 #include <sys/types.h>
33 #include "pwmd-error.h"
37 #include "util-misc.h"
39 #include "util-slist.h"
40 #include "util-string.h"
43 #define DEFAULT_PINENTRY_TIMEOUT "30"
44 #define DEFAULT_CACHE_TIMEOUT "600"
45 #define DEFAULT_KEEPALIVE_INTERVAL "60"
47 #define INVALID_VALUE(file, line) do { \
49 log_write(_("%s(%i): invalid value for parameter."), file, line); \
54 PARAM_INT
, PARAM_CHARP
, PARAM_LONG
, PARAM_LONGLONG
, PARAM_CHARPP
,
55 PARAM_BOOL
, PARAM_ULONG
, PARAM_ULONGLONG
58 static struct config_params_s
64 { "backup", PARAM_BOOL
, "true"},
65 { "socket_path", PARAM_CHARP
, NULL
},
66 { "socket_perms", PARAM_CHARP
, NULL
},
67 { "passphrase", PARAM_CHARP
, NULL
},
68 { "passphrase_file", PARAM_CHARP
, NULL
},
69 { "agent_env_file", PARAM_CHARP
, NULL
},
70 { "log_path", PARAM_CHARP
, "~/.pwmd/log"},
71 { "enable_logging", PARAM_BOOL
, "0"},
72 { "log_keepopen", PARAM_BOOL
, "true"},
73 { "log_level", PARAM_INT
, "0"},
74 { "disable_mlockall", PARAM_BOOL
, "true"},
75 { "cache_timeout", PARAM_INT
, DEFAULT_CACHE_TIMEOUT
},
76 { "cache_push", PARAM_CHARPP
, NULL
},
77 { "disable_list_and_dump", PARAM_BOOL
, "false"},
78 { "recursion_depth", PARAM_INT
, "100"},
79 { "syslog", PARAM_BOOL
, "false"},
80 { "xfer_progress", PARAM_INT
, "8196"},
81 { "allowed", PARAM_CHARPP
, NULL
},
82 { "allowed_file", PARAM_CHARP
, NULL
},
83 { "keyparam", PARAM_CHARP
, "(genkey (rsa (nbits 4:2048)))"},
84 { "cipher", PARAM_CHARP
, "aes256"},
85 { "kill_scd", PARAM_BOOL
, "false"},
86 { "cipher_iterations", PARAM_ULONGLONG
, "0"},
87 { "cipher_progress", PARAM_LONG
, DEFAULT_ITERATION_PROGRESS
},
88 { "priority", PARAM_INT
, INVALID_PRIORITY
},
89 { "keepalive_interval", PARAM_INT
, DEFAULT_KEEPALIVE_INTERVAL
},
90 { "tcp_port", PARAM_INT
, "6466"},
91 { "enable_tcp", PARAM_BOOL
, "false"},
92 { "tcp_require_key", PARAM_BOOL
, "false"},
93 { "tcp_wait", PARAM_INT
, "0"},
94 { "tcp_bind", PARAM_CHARP
, "any"},
95 { "tcp_interface", PARAM_CHARP
, NULL
},
96 { "tls_timeout", PARAM_INT
, "300"},
97 { "tls_cipher_suite", PARAM_CHARP
, "SECURE256"},
98 { "pinentry_path", PARAM_CHARP
, PINENTRY_PATH
},
99 { "pinentry_timeout", PARAM_INT
, DEFAULT_PINENTRY_TIMEOUT
},
100 { "use_agent", PARAM_BOOL
, "false"},
101 { "require_save_key", PARAM_BOOL
, "true"},
102 { "invoking_user", PARAM_CHARP
, NULL
},
103 { "invoking_tls", PARAM_CHARP
, NULL
},
107 struct config_param_s
118 unsigned long ultype
;
119 unsigned long long ulltype
;
123 static struct config_section_s
*config_find_section (struct slist_s
*config
,
125 static int new_param (struct config_section_s
*section
, const char *filename
,
126 int lineno
, const char *name
, const char *value
,
128 static void free_section (struct config_section_s
*s
);
129 static int set_defaults (struct slist_s
**config
);
132 section_remove_param (struct config_section_s
*section
, const char *name
)
134 unsigned i
, t
= slist_length (section
->params
);
136 for (i
= 0; i
< t
; i
++)
138 struct config_param_s
*p
= slist_nth_data (section
->params
, i
);
143 if (!strcmp (p
->name
, name
))
148 xfree (p
->value
.cptype
);
151 strv_free (p
->value
.cpptype
);
155 section
->params
= slist_remove (section
->params
, p
);
166 MUTEX_LOCK (&rcfile_mutex
);
167 unsigned i
, t
= slist_length (global_config
);
169 for (i
= 0; i
< t
; i
++)
171 struct config_section_s
*s
= slist_nth_data (global_config
, i
);
175 section_remove_param (s
, "passphrase");
178 MUTEX_UNLOCK (&rcfile_mutex
);
181 static struct config_param_s
*
182 config_has_param (struct config_section_s
*s
, const char *what
)
184 unsigned i
, t
= slist_length (s
->params
);
186 for (i
= 0; i
< t
; i
++)
188 struct config_param_s
*p
= slist_nth_data (s
->params
, i
);
192 if (!strcmp (p
->name
, what
))
199 static struct config_param_s
*
200 config_get_param (struct slist_s
*config
,
201 const char *section
, const char *what
, int *exists
)
203 unsigned i
, t
= slist_length (config
);
207 for (i
= 0; i
< t
; i
++)
209 struct config_param_s
*p
;
210 struct config_section_s
*s
= slist_nth_data (config
, i
);
215 if (strcmp (s
->name
, section
))
218 p
= config_has_param (s
, what
);
229 static struct config_section_s
*
230 new_section (struct slist_s
**config
, const char *name
)
233 struct config_section_s
*s
= xcalloc (1, sizeof (struct config_section_s
));
238 s
->name
= str_dup (name
);
241 log_write ("%s", pwmd_strerror (ENOMEM
));
246 tmp
= slist_append (*config
, s
);
249 log_write ("%s", pwmd_strerror (ENOMEM
));
260 config_set_string_param (struct slist_s
**config
, const char *section
,
261 const char *name
, const char *value
)
263 struct config_section_s
*s
= config_find_section (*config
, section
);
267 s
= new_section (config
, section
);
272 return new_param (s
, NULL
, 0, name
, value
, PARAM_CHARP
);
276 config_get_string_param (struct slist_s
*config
, const char *section
,
277 const char *what
, int *exists
)
279 struct config_param_s
*p
= config_get_param (config
, section
, what
, exists
);
280 return *exists
&& p
->value
.cptype
? str_dup (p
->value
.cptype
) : NULL
;
284 config_set_int_param (struct slist_s
**config
, const char *section
,
285 const char *name
, const char *value
)
287 struct config_section_s
*s
= config_find_section (*config
, section
);
291 s
= new_section (config
, section
);
296 return new_param (s
, NULL
, 0, name
, value
, PARAM_INT
);
300 config_get_int_param (struct slist_s
*config
, const char *section
,
301 const char *what
, int *exists
)
303 struct config_param_s
*p
= config_get_param (config
, section
, what
, exists
);
304 return *exists
? p
->value
.itype
: -1;
308 config_set_bool_param (struct slist_s
**config
, const char *section
,
309 const char *name
, const char *value
)
311 struct config_section_s
*s
= config_find_section (*config
, section
);
315 s
= new_section (config
, section
);
320 return new_param (s
, NULL
, 0, name
, value
, PARAM_BOOL
);
324 config_get_bool_param (struct slist_s
*config
, const char *section
,
325 const char *what
, int *exists
)
327 return config_get_int_param (config
, section
, what
, exists
);
331 config_set_long_param (struct slist_s
**config
, const char *section
,
332 const char *name
, const char *value
)
334 struct config_section_s
*s
= config_find_section (*config
, section
);
338 s
= new_section (config
, section
);
343 return new_param (s
, NULL
, 0, name
, value
, PARAM_LONG
);
347 config_get_ulong_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
.ultype
: 0;
355 config_get_long_param (struct slist_s
*config
, const char *section
,
356 const char *what
, int *exists
)
358 struct config_param_s
*p
= config_get_param (config
, section
, what
, exists
);
359 return *exists
? p
->value
.ltype
: -1;
363 config_set_longlong_param (struct slist_s
**config
, const char *section
,
364 const char *name
, const char *value
)
366 struct config_section_s
*s
= config_find_section (*config
, section
);
370 s
= new_section (config
, section
);
375 return new_param (s
, NULL
, 0, name
, value
, PARAM_LONGLONG
);
379 config_get_longlong_param (struct slist_s
*config
,
380 const char *section
, const char *what
, int *exists
)
382 struct config_param_s
*p
= config_get_param (config
, section
, what
, exists
);
383 return *exists
? p
->value
.lltype
: -1;
387 config_get_ulonglong_param (struct slist_s
*config
,
389 const char *what
, int *exists
)
391 struct config_param_s
*p
= config_get_param (config
, section
, what
, exists
);
392 return *exists
? p
->value
.ulltype
: 0;
396 config_set_list_param (struct slist_s
**config
, const char *section
,
397 const char *name
, const char *value
)
399 struct config_section_s
*s
= config_find_section (*config
, section
);
403 s
= new_section (config
, section
);
408 return new_param (s
, NULL
, 0, name
, value
, PARAM_CHARPP
);
412 config_get_list_param (struct slist_s
*config
, const char *section
,
413 const char *what
, int *exists
)
415 struct config_param_s
*p
= config_get_param (config
, section
, what
, exists
);
416 return *exists
&& p
->value
.cpptype
? strv_dup (p
->value
.cpptype
) : NULL
;
420 config_get_string (const char *section
, const char *what
)
423 const char *where
= section
? section
: "global";
426 MUTEX_LOCK (&rcfile_mutex
);
427 val
= config_get_string_param (global_config
, where
, what
, &exists
);
428 if (!exists
&& strcmp (section
? section
: "", "global"))
429 val
= config_get_string_param (global_config
, "global", what
, &exists
);
431 MUTEX_UNLOCK (&rcfile_mutex
);
436 config_get_list (const char *section
, const char *what
)
439 const char *where
= section
? section
: "global";
442 MUTEX_LOCK (&rcfile_mutex
);
443 val
= config_get_list_param (global_config
, where
, what
, &exists
);
444 if (!exists
&& strcmp (section
? section
: "", "global"))
445 val
= config_get_list_param (global_config
, "global", what
, &exists
);
447 MUTEX_UNLOCK (&rcfile_mutex
);
452 config_get_integer (const char *section
, const char *what
)
455 const char *where
= section
? section
: "global";
458 MUTEX_LOCK (&rcfile_mutex
);
459 val
= config_get_int_param (global_config
, where
, what
, &exists
);
460 if (!exists
&& strcmp (section
? section
: "", "global"))
461 val
= config_get_int_param (global_config
, "global", what
, &exists
);
463 MUTEX_UNLOCK (&rcfile_mutex
);
468 config_get_longlong (const char *section
, const char *what
)
471 const char *where
= section
? section
: "global";
474 MUTEX_LOCK (&rcfile_mutex
);
475 val
= config_get_longlong_param (global_config
, where
, what
, &exists
);
476 if (!exists
&& strcmp (section
? section
: "", "global"))
477 val
= config_get_longlong_param (global_config
, "global", what
, &exists
);
479 MUTEX_UNLOCK (&rcfile_mutex
);
484 config_get_ulonglong (const char *section
, const char *what
)
486 unsigned long long val
= 0;
487 const char *where
= section
? section
: "global";
490 MUTEX_LOCK (&rcfile_mutex
);
491 val
= config_get_ulonglong_param (global_config
, where
, what
, &exists
);
492 if (!exists
&& strcmp (section
? section
: "", "global"))
493 val
= config_get_ulonglong_param (global_config
, "global", what
, &exists
);
495 MUTEX_UNLOCK (&rcfile_mutex
);
500 config_get_long (const char *section
, const char *what
)
503 const char *where
= section
? section
: "global";
506 MUTEX_LOCK (&rcfile_mutex
);
507 val
= config_get_long_param (global_config
, where
, what
, &exists
);
508 if (!exists
&& strcmp (section
? section
: "", "global"))
509 val
= config_get_long_param (global_config
, "global", what
, &exists
);
511 MUTEX_UNLOCK (&rcfile_mutex
);
516 config_get_ulong (const char *section
, const char *what
)
518 unsigned long val
= 0;
519 const char *where
= section
? section
: "global";
522 MUTEX_LOCK (&rcfile_mutex
);
523 val
= config_get_ulong_param (global_config
, where
, what
, &exists
);
524 if (!exists
&& strcmp (section
? section
: "", "global"))
525 val
= config_get_ulong_param (global_config
, "global", what
, &exists
);
527 MUTEX_UNLOCK (&rcfile_mutex
);
532 config_get_boolean (const char *section
, const char *what
)
534 return config_get_integer (section
, what
);
538 config_get_value (const char *section
, const char *what
)
540 const char *where
= section
? section
: "global";
547 unsigned long long ullval
;
552 MUTEX_LOCK (&rcfile_mutex
);
554 for (i
= 0; config_params
[i
].name
; i
++)
556 if (!strcmp (config_params
[i
].name
, what
))
558 switch (config_params
[i
].type
)
562 ival
= config_get_int_param (global_config
, where
, what
,
564 if (!exists
&& strcmp (section
? section
: "", "global"))
565 ival
= config_get_int_param (global_config
, "global", what
,
567 result
= str_asprintf ("%i", ival
);
570 cpval
= config_get_string_param (global_config
, where
, what
,
572 if (!exists
&& strcmp (section
? section
: "", "global"))
574 config_get_string_param (global_config
, "global", what
,
579 lval
= config_get_long_param (global_config
, where
, what
,
581 if (!exists
&& strcmp (section
? section
: "", "global"))
582 lval
= config_get_long_param (global_config
, "global", what
,
584 result
= str_asprintf ("%li", lval
);
587 ulval
= config_get_ulong_param (global_config
, where
, what
,
589 if (!exists
&& strcmp (section
? section
: "", "global"))
590 ulval
= config_get_ulong_param (global_config
, "global", what
,
592 result
= str_asprintf ("%lu", ulval
);
595 llval
= config_get_longlong_param (global_config
, where
, what
,
597 if (!exists
&& strcmp (section
? section
: "", "global"))
598 llval
= config_get_longlong_param (global_config
, "global",
600 result
= str_asprintf ("%lli", llval
);
602 case PARAM_ULONGLONG
:
603 ullval
= config_get_ulonglong_param (global_config
, where
, what
,
605 if (!exists
&& strcmp (section
? section
: "", "global"))
606 ullval
= config_get_ulonglong_param (global_config
, "global",
608 result
= str_asprintf ("%llu", ullval
);
611 cppval
= config_get_list_param (global_config
, where
, what
,
613 if (!exists
&& strcmp (section
? section
: "", "global"))
614 cppval
= config_get_list_param (global_config
, "global", what
,
618 result
= strv_join (",", cppval
);
626 MUTEX_UNLOCK (&rcfile_mutex
);
631 parse_allowed_file (struct slist_s
*config
, const char *section
)
638 char *p
= config_get_string_param (config
, section
, "allowed_file", &exists
);
646 tmp
= expand_homedir (p
);
652 log_write ("%s: %s", p
, strerror (errno
));
658 list
= config_get_list_param (config
, section
, "allowed", &exists
);
662 log_write ("%s", strerror (ENOMEM
));
666 while ((p
= fgets (buf
, sizeof (buf
), fp
)))
670 if (p
[strlen(p
)-1] == '\n')
673 while (*p
&& isspace (*p
))
681 pp
= strv_cat (list
, str_dup (p
));
688 log_write ("%s", strerror (ENOMEM
));
700 p
= strv_join (",", list
);
705 log_write ("%s", strerror (ENOMEM
));
709 config_set_list_param (&config
, section
, "allowed", p
);
714 fixup_allowed_once (struct slist_s
**config
, const char *section
)
716 char **list
, **pp
, *p
;
719 parse_allowed_file (*config
, section
);
720 list
= config_get_list_param (*config
, section
, "allowed", &exists
);
721 for (pp
= list
; pp
&& *pp
; pp
++)
725 for (p
= *pp
; p
&& *p
; p
++)
733 if (!strcmp (section
, "global"))
735 p
= get_username (getuid());
737 if (config_set_list_param (config
, section
, "allowed", p
))
747 list
= config_get_list_param (*config
, "global", "allowed", &exists
);
748 p
= strv_join (",", list
);
750 if (config_set_list_param (config
, section
, "allowed", p
))
764 fixup_allowed (struct slist_s
**config
)
766 int n
, t
= slist_length (*config
);
768 for (n
= 0; n
< t
; n
++)
770 struct config_section_s
*section
;
772 section
= slist_nth_data (*config
, n
);
773 if (fixup_allowed_once (config
, section
->name
))
781 set_defaults (struct slist_s
**config
)
789 for (i
= 0; config_params
[i
].name
; i
++)
791 switch (config_params
[i
].type
)
794 config_get_bool_param (*config
, "global", config_params
[i
].name
,
798 if (config_set_bool_param
799 (config
, "global", config_params
[i
].name
,
800 config_params
[i
].value
))
805 config_get_int_param (*config
, "global", config_params
[i
].name
,
809 if (config_set_int_param
810 (config
, "global", config_params
[i
].name
,
811 config_params
[i
].value
))
816 s
= config_get_string_param (*config
, "global",
817 config_params
[i
].name
, &exists
);
819 if (!exists
&& config_params
[i
].value
)
821 if (config_set_string_param (config
, "global",
822 config_params
[i
].name
,
823 config_params
[i
].value
))
828 list
= config_get_list_param (*config
, "global",
829 config_params
[i
].name
, &exists
);
831 if (!exists
&& config_params
[i
].value
)
833 if (config_set_list_param (config
, "global",
834 config_params
[i
].name
,
835 config_params
[i
].value
))
840 config_get_long_param (*config
, "global", config_params
[i
].name
,
844 if (config_set_long_param
845 (config
, "global", config_params
[i
].name
,
846 config_params
[i
].value
))
851 config_get_longlong_param (*config
, "global", config_params
[i
].name
,
855 if (config_set_longlong_param (config
, "global",
856 config_params
[i
].name
,
857 config_params
[i
].value
))
865 if (fixup_allowed (config
))
868 max_recursion_depth
= config_get_int_param (*config
, "global",
869 "recursion_depth", &exists
);
870 disable_list_and_dump
= config_get_bool_param (*config
, "global",
871 "disable_list_and_dump",
875 config_get_bool_param (*config
, "global", "disable_mlockall", &exists
);
878 s
= config_get_string_param(*config
, "global", "invoking_user", &exists
);
881 pwd
= getpwuid(getuid());
887 log_write (_("could not set invoking user: user '%s' is invalid"), s
);
893 invoking_tls
= config_get_string_param(*config
, "global", "invoking_tls",
895 for (p
= invoking_tls
; p
&& *p
; p
++)
899 invoking_uid
= pwd
->pw_uid
;
900 invoking_gid
= pwd
->pw_gid
;
908 static struct config_section_s
*
909 config_find_section (struct slist_s
*config
, const char *name
)
911 unsigned i
, t
= slist_length (config
);
913 for (i
= 0; i
< t
; i
++)
915 struct config_section_s
*s
= slist_nth_data (config
, i
);
917 if (!strcmp (s
->name
, name
))
924 /* Append a new parameter to the list of parameters for a file
925 * section. When an existing parameter of the same name exists, its
929 new_param (struct config_section_s
*section
, const char *filename
, int lineno
,
930 const char *name
, const char *value
, int type
)
932 struct config_param_s
*param
= NULL
;
935 unsigned i
, t
= slist_length (section
->params
);
938 for (i
= 0; i
< t
; i
++)
940 struct config_param_s
*p
= slist_nth_data (section
->params
, i
);
944 if (!strcmp (name
, p
->name
))
954 param
= xcalloc (1, sizeof (struct config_param_s
));
957 log_write ("%s", pwmd_strerror (ENOMEM
));
961 param
->name
= str_dup (name
);
965 log_write ("%s", pwmd_strerror (ENOMEM
));
975 if (!strcasecmp (value
, "no") || !strcasecmp (value
, "0")
976 || !strcasecmp (value
, "false"))
977 param
->value
.itype
= 0;
978 else if (!strcasecmp (value
, "yes") || !strcasecmp (value
, "1")
979 || !strcasecmp (value
, "true"))
980 param
->value
.itype
= 1;
983 INVALID_VALUE (filename
, lineno
);
986 param
->type
= PARAM_INT
;
989 xfree (param
->value
.cptype
);
990 param
->value
.cptype
= NULL
;
991 param
->value
.cptype
= value
&& *value
? str_dup (value
) : NULL
;
992 if (value
&& *value
&& !param
->value
.cptype
)
994 log_write ("%s", pwmd_strerror (ENOMEM
));
999 strv_free (param
->value
.cpptype
);
1000 param
->value
.cpptype
= NULL
;
1001 param
->value
.cpptype
= value
&& *value
? str_split (value
, ",", 0) : NULL
;
1002 if (value
&& *value
&& !param
->value
.cpptype
)
1004 log_write ("%s", pwmd_strerror (ENOMEM
));
1009 param
->value
.itype
= strtol (value
, &e
, 10);
1012 INVALID_VALUE (filename
, lineno
);
1017 param
->value
.ltype
= strtol (value
, &e
, 10);
1020 INVALID_VALUE (filename
, lineno
);
1024 case PARAM_LONGLONG
:
1025 param
->value
.lltype
= strtoll (value
, &e
, 10);
1028 INVALID_VALUE (filename
, lineno
);
1032 case PARAM_ULONGLONG
:
1033 param
->value
.ulltype
= strtoull (value
, &e
, 10);
1036 INVALID_VALUE (filename
, lineno
);
1041 param
->value
.ultype
= strtoul (value
, &e
, 10);
1044 INVALID_VALUE (filename
, lineno
);
1053 tmp
= slist_append (section
->params
, param
);
1056 log_write ("%s", pwmd_strerror (ENOMEM
));
1060 section
->params
= tmp
;
1064 xfree (param
->name
);
1070 config_parse (const char *filename
)
1072 struct slist_s
*tmpconfig
= NULL
, *tmp
;
1073 struct config_section_s
*cur_section
= NULL
;
1077 int have_global
= 0;
1078 FILE *fp
= fopen (filename
, "r");
1082 log_write ("%s: %s", filename
,
1083 pwmd_strerror (gpg_error_from_errno (errno
)));
1085 if (errno
!= ENOENT
)
1088 log_write (_("Using defaults!"));
1092 for (; (s
= fgets (buf
, sizeof (buf
), fp
)); lineno
++)
1094 char line
[LINE_MAX
] = { 0 };
1101 for (; s
&& *s
; s
++)
1105 /* New file section. */
1108 struct config_section_s
*section
;
1109 char *p
= strchr (++s
, ']');
1113 log_write (_("%s(%i): unbalanced braces"), filename
,
1118 len
= strlen (s
) - strlen (p
);
1119 memcpy (line
, s
, len
);
1122 section
= config_find_section (tmpconfig
, line
);
1125 log_write (_("%s(%i): section '%s' already exists!"),
1126 filename
, lineno
, line
);
1130 if (!strcmp (line
, "global"))
1133 section
= xcalloc (1, sizeof (struct config_section_s
));
1134 section
->name
= str_dup (line
);
1138 tmp
= slist_append (tmpconfig
, cur_section
);
1141 log_write ("%s", pwmd_strerror (ENOMEM
));
1148 cur_section
= section
;
1154 log_write (_("%s(%i): parameter outside of section!"), filename
,
1159 /* Parameters for each section. */
1160 for (int m
= 0; config_params
[m
].name
; m
++)
1162 size_t len
= strlen (config_params
[m
].name
);
1164 if (!strncmp (s
, config_params
[m
].name
, len
))
1168 while (*p
&& *p
== ' ')
1171 if (!*p
|| *p
!= '=')
1175 while (*p
&& isspace (*p
))
1179 if (new_param (cur_section
, filename
, lineno
, s
, p
,
1180 config_params
[m
].type
))
1190 log_write (_("%s(%i): unknown parameter"), filename
, lineno
);
1200 tmp
= slist_append (tmpconfig
, cur_section
);
1203 log_write ("%s", pwmd_strerror (ENOMEM
));
1213 ("WARNING: %s: could not find a [global] configuration section!"),
1217 if (set_defaults (&tmpconfig
))
1229 config_free (tmpconfig
);
1230 free_section (cur_section
);
1235 free_section (struct config_section_s
*s
)
1242 struct config_param_s
*p
= slist_nth_data (s
->params
, 0);
1247 section_remove_param (s
, p
->name
);
1256 config_free (struct slist_s
*config
)
1260 struct config_section_s
*s
= slist_nth_data (config
, 0);
1265 config
= slist_remove (config
, s
);