Home | History | Annotate | Line # | Download | only in global
      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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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