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