xref: /netbsd-src/external/ibm-public/postfix/dist/src/global/cfg_parser.c (revision e89934bbf778a6d6d6894877c4da59d0c7835b0f)
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