1 /* $NetBSD: cfg_parser.c,v 1.2 2017/02/14 01:16:45 christos Exp $ */
2
3 /*++
4 /* NAME
5 /* cfg_parser 3
6 /* SUMMARY
7 /* configuration parser utilities
8 /* SYNOPSIS
9 /* #include "cfg_parser.h"
10 /*
11 /* CFG_PARSER *cfg_parser_alloc(pname)
12 /* const char *pname;
13 /*
14 /* CFG_PARSER *cfg_parser_free(parser)
15 /* CFG_PARSER *parser;
16 /*
17 /* char *cfg_get_str(parser, name, defval, min, max)
18 /* const CFG_PARSER *parser;
19 /* const char *name;
20 /* const char *defval;
21 /* int min;
22 /* int max;
23 /*
24 /* int cfg_get_int(parser, name, defval, min, max)
25 /* const CFG_PARSER *parser;
26 /* const char *name;
27 /* int defval;
28 /* int min;
29 /* int max;
30 /*
31 /* int cfg_get_bool(parser, name, defval)
32 /* const CFG_PARSER *parser;
33 /* const char *name;
34 /* int defval;
35 /*
36 /* DICT_OWNER cfg_get_owner(parser)
37 /* const CFG_PARSER *parser;
38 /* DESCRIPTION
39 /* This module implements utilities for parsing parameters defined
40 /* either as "\fIname\fR = \fBvalue\fR" in a file pointed to by
41 /* \fIpname\fR (the old MySQL style), or as "\fIpname\fR_\fIname\fR =
42 /* \fBvalue\fR" in main.cf (the old LDAP style). It unifies the
43 /* two styles and provides support for range checking.
44 /*
45 /* \fIcfg_parser_alloc\fR initializes the parser. The result
46 /* is NULL if a configuration file could not be opened.
47 /*
48 /* \fIcfg_parser_free\fR releases the parser.
49 /*
50 /* \fIcfg_get_str\fR looks up a string.
51 /*
52 /* \fIcfg_get_int\fR looks up an integer.
53 /*
54 /* \fIcfg_get_bool\fR looks up a boolean value.
55 /*
56 /* \fIdefval\fR is returned when no value was found. \fImin\fR is
57 /* zero or specifies a lower limit on the integer value or string
58 /* length; \fImax\fR is zero or specifies an upper limit on the
59 /* integer value or string length.
60 /*
61 /* Conveniently, \fIcfg_get_str\fR returns \fBNULL\fR if
62 /* \fIdefval\fR is \fBNULL\fR and no value was found. The returned
63 /* string has to be freed by the caller if not \fBNULL\fR.
64 /*
65 /* cfg_get_owner() looks up the configuration file owner.
66 /* DIAGNOSTICS
67 /* Fatal errors: bad string length, malformed numerical value, malformed
68 /* boolean value.
69 /* SEE ALSO
70 /* mail_conf_str(3) string-valued global configuration parameter support
71 /* mail_conf_int(3) integer-valued configuration parameter support
72 /* mail_conf_bool(3) boolean-valued configuration parameter support
73 /* LICENSE
74 /* .ad
75 /* .fi
76 /* The Secure Mailer license must be distributed with this software.
77 /* AUTHOR(S)
78 /* Wietse Venema
79 /* IBM T.J. Watson Research
80 /* P.O. Box 704
81 /* Yorktown Heights, NY 10598, USA
82 /*
83 /* Liviu Daia
84 /* Institute of Mathematics of the Romanian Academy
85 /* P.O. BOX 1-764
86 /* RO-014700 Bucharest, ROMANIA
87 /*--*/
88
89 /* System library. */
90
91 #include "sys_defs.h"
92
93 #include <stdlib.h>
94 #include <errno.h>
95 #include <string.h>
96
97 #ifdef STRCASECMP_IN_STRINGS_H
98 #include <strings.h>
99 #endif
100
101 /* Utility library. */
102
103 #include "msg.h"
104 #include "mymalloc.h"
105 #include "vstring.h"
106 #include "dict.h"
107
108 /* Global library. */
109
110 #include "mail_conf.h"
111
112 /* Application-specific. */
113
114 #include "cfg_parser.h"
115
116 /* get string from file */
117
get_dict_str(const struct CFG_PARSER * parser,const char * name,const char * defval,int min,int max)118 static char *get_dict_str(const struct CFG_PARSER *parser,
119 const char *name, const char *defval,
120 int min, int max)
121 {
122 const char *strval;
123 int len;
124
125 if ((strval = dict_lookup(parser->name, name)) == 0)
126 strval = defval;
127
128 len = strlen(strval);
129 if (min && len < min)
130 msg_fatal("%s: bad string length %d < %d: %s = %s",
131 parser->name, len, min, name, strval);
132 if (max && len > max)
133 msg_fatal("%s: bad string length %d > %d: %s = %s",
134 parser->name, len, max, name, strval);
135 return (mystrdup(strval));
136 }
137
138 /* get string from main.cf */
139
get_main_str(const struct CFG_PARSER * parser,const char * name,const char * defval,int min,int max)140 static char *get_main_str(const struct CFG_PARSER *parser,
141 const char *name, const char *defval,
142 int min, int max)
143 {
144 static VSTRING *buf = 0;
145
146 if (buf == 0)
147 buf = vstring_alloc(15);
148 vstring_sprintf(buf, "%s_%s", parser->name, name);
149 return (get_mail_conf_str(vstring_str(buf), defval, min, max));
150 }
151
152 /* get integer from file */
153
get_dict_int(const struct CFG_PARSER * parser,const char * name,int defval,int min,int max)154 static int get_dict_int(const struct CFG_PARSER *parser,
155 const char *name, int defval, int min, int max)
156 {
157 const char *strval;
158 char *end;
159 int intval;
160 long longval;
161
162 if ((strval = dict_lookup(parser->name, name)) != 0) {
163 errno = 0;
164 intval = longval = strtol(strval, &end, 10);
165 if (*strval == 0 || *end != 0 || errno == ERANGE || longval != intval)
166 msg_fatal("%s: bad numerical configuration: %s = %s",
167 parser->name, name, strval);
168 } else
169 intval = defval;
170 if (min && intval < min)
171 msg_fatal("%s: invalid %s parameter value %d < %d",
172 parser->name, name, intval, min);
173 if (max && intval > max)
174 msg_fatal("%s: invalid %s parameter value %d > %d",
175 parser->name, name, intval, max);
176 return (intval);
177 }
178
179 /* get integer from main.cf */
180
get_main_int(const struct CFG_PARSER * parser,const char * name,int defval,int min,int max)181 static int get_main_int(const struct CFG_PARSER *parser,
182 const char *name, int defval, int min, int max)
183 {
184 static VSTRING *buf = 0;
185
186 if (buf == 0)
187 buf = vstring_alloc(15);
188 vstring_sprintf(buf, "%s_%s", parser->name, name);
189 return (get_mail_conf_int(vstring_str(buf), defval, min, max));
190 }
191
192 /* get boolean option from file */
193
get_dict_bool(const struct CFG_PARSER * parser,const char * name,int defval)194 static int get_dict_bool(const struct CFG_PARSER *parser,
195 const char *name, int defval)
196 {
197 const char *strval;
198 int intval;
199
200 if ((strval = dict_lookup(parser->name, name)) != 0) {
201 if (strcasecmp(strval, CONFIG_BOOL_YES) == 0) {
202 intval = 1;
203 } else if (strcasecmp(strval, CONFIG_BOOL_NO) == 0) {
204 intval = 0;
205 } else {
206 msg_fatal("%s: bad boolean configuration: %s = %s",
207 parser->name, name, strval);
208 }
209 } else
210 intval = defval;
211 return (intval);
212 }
213
214 /* get boolean option from main.cf */
215
get_main_bool(const struct CFG_PARSER * parser,const char * name,int defval)216 static int get_main_bool(const struct CFG_PARSER *parser,
217 const char *name, int defval)
218 {
219 static VSTRING *buf = 0;
220
221 if (buf == 0)
222 buf = vstring_alloc(15);
223 vstring_sprintf(buf, "%s_%s", parser->name, name);
224 return (get_mail_conf_bool(vstring_str(buf), defval));
225 }
226
227 /* initialize parser */
228
cfg_parser_alloc(const char * pname)229 CFG_PARSER *cfg_parser_alloc(const char *pname)
230 {
231 const char *myname = "cfg_parser_alloc";
232 CFG_PARSER *parser;
233 DICT *dict;
234
235 if (pname == 0 || *pname == 0)
236 msg_fatal("%s: null parser name", myname);
237 parser = (CFG_PARSER *) mymalloc(sizeof(*parser));
238 parser->name = mystrdup(pname);
239 if (*parser->name == '/' || *parser->name == '.') {
240 if (dict_load_file_xt(parser->name, parser->name) == 0) {
241 myfree(parser->name);
242 myfree((void *) parser);
243 return (0);
244 }
245 parser->get_str = get_dict_str;
246 parser->get_int = get_dict_int;
247 parser->get_bool = get_dict_bool;
248 dict = dict_handle(parser->name);
249 } else {
250 parser->get_str = get_main_str;
251 parser->get_int = get_main_int;
252 parser->get_bool = get_main_bool;
253 dict = dict_handle(CONFIG_DICT); /* XXX Use proper API */
254 }
255 if (dict == 0)
256 msg_panic("%s: dict_handle failed", myname);
257 parser->owner = dict->owner;
258 return (parser);
259 }
260
261 /* get string */
262
cfg_get_str(const CFG_PARSER * parser,const char * name,const char * defval,int min,int max)263 char *cfg_get_str(const CFG_PARSER *parser, const char *name,
264 const char *defval, int min, int max)
265 {
266 const char *myname = "cfg_get_str";
267 char *strval;
268
269 strval = parser->get_str(parser, name, (defval ? defval : ""), min, max);
270 if (defval == 0 && *strval == 0) {
271 /* the caller wants NULL instead of "" */
272 myfree(strval);
273 strval = 0;
274 }
275 if (msg_verbose)
276 msg_info("%s: %s: %s = %s", myname, parser->name, name,
277 (strval ? strval : "<NULL>"));
278 return (strval);
279 }
280
281 /* get integer */
282
cfg_get_int(const CFG_PARSER * parser,const char * name,int defval,int min,int max)283 int cfg_get_int(const CFG_PARSER *parser, const char *name, int defval,
284 int min, int max)
285 {
286 const char *myname = "cfg_get_int";
287 int intval;
288
289 intval = parser->get_int(parser, name, defval, min, max);
290 if (msg_verbose)
291 msg_info("%s: %s: %s = %d", myname, parser->name, name, intval);
292 return (intval);
293 }
294
295 /* get boolean option */
296
cfg_get_bool(const CFG_PARSER * parser,const char * name,int defval)297 int cfg_get_bool(const CFG_PARSER *parser, const char *name, int defval)
298 {
299 const char *myname = "cfg_get_bool";
300 int intval;
301
302 intval = parser->get_bool(parser, name, defval);
303 if (msg_verbose)
304 msg_info("%s: %s: %s = %s", myname, parser->name, name,
305 (intval ? "on" : "off"));
306 return (intval);
307 }
308
309 /* release parser */
310
cfg_parser_free(CFG_PARSER * parser)311 CFG_PARSER *cfg_parser_free(CFG_PARSER *parser)
312 {
313 const char *myname = "cfg_parser_free";
314
315 if (parser->name == 0 || *parser->name == 0)
316 msg_panic("%s: null parser name", myname);
317 if (*parser->name == '/' || *parser->name == '.') {
318 if (dict_handle(parser->name))
319 dict_unregister(parser->name);
320 }
321 myfree(parser->name);
322 myfree((void *) parser);
323 return (0);
324 }
325