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