/* * Copyright (c) 2004, 2005 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set * forth in the LICENSE file which can be found at the top level of * the sendmail distribution. */ #define SM_SMARCNFDEF 1 #include "sm/generic.h" SM_RCSID("@(#)$Id: smarconf.c,v 1.41 2007/11/14 06:03:09 ca Exp $") #include "sm/error.h" #include "sm/assert.h" #include "sm/sysexits.h" #include "sm/string.h" #include "sm/ctype.h" #include "sm/io.h" #include "sm/misc.h" #include "log.h" #include "sm/qmgrcomm.h" #include "sm/sm-conf.h" #include "sm/sm-conf-prt.h" #define SM_LOG_IDENT "smar" #define SM_CONF_TIME_DEF 1 #define SM_CONF_LOG_DEF 1 #define SM_MAPCNFDEF 1 #define SM_GREYCNFDEF 1 #include "smar.h" #include "sm/map.h" #include "sm/mapconf.h" #include "sm/mapcnf.h" #include "sm/mapcnfdef.h" #include "sm/greycnf.h" #include "sm/greycnfdef.h" #include "sm/smarcnf.h" #include "sm/smarcnfdef.h" /* ** SMAR_READ_CNF -- Read configuration file ** ** Parameters: ** smar_ctx -- SMAR context ** fn -- filename of configuration file ** psmc -- (pointer to) configuration context (output) ** ** Returns: ** 0 on success, everything else is an error */ sm_ret_T smar_read_cnf(smar_ctx_P smar_ctx, const char *fn, sm_conf_T **psmc) { int err; sm_ret_T ret; uint ui; uchar uc, *us; char *s; sm_conf_T *smc; sm_conf_iterator_T cnf_iter; FILE *fp; char confdir[PATH_MAX]; fp = NULL; smc = sm_conf_new(fn); if (NULL == smc) { err = errno; sm_io_fprintf(smioerr, "sev=ERROR, func=smar_read_cnf, file=%.256s, sm_conf_new=NULL, errno=%d\n", fn, err); return sm_error_temp(SM_EM_Q_CONF, ENOMEM); } err = sm_conf_read_FILE(smc, fn, fp); if (err != 0) { sm_prt_conferr(fn, smc, err, smioerr); goto error; } err = sm_conf_scan(smc, smar_global_defs, SM_CONF_FLAG_ALLOW_ANY, &smar_ctx->smar_cnf); if (err != 0) { sm_prt_conferr(fn, smc, err, smioerr); goto error; } /* ** HACK: "parse" configuration data. ** This will go away as soon as the configuration ** definition evolves... (array of IPv4 addresses) */ while ((ui = smar_ctx->smar_dns_ntsks) < SM_DNS_MAX_TSKS && (s = smar_ctx->smar_cnf.smar_cnf_nameservers[ui]) != NULL) { smar_ctx->smar_nameserveripv4s[ui] = (ipv4_T) inet_addr(s); ++smar_ctx->smar_dns_ntsks; } if (smar_ctx->smar_cnf.smar_cnf_hostname != NULL) { size_t l; l = strlen(smar_ctx->smar_cnf.smar_cnf_hostname) + 1; smar_ctx->smar_hostname = sm_str_scpyn0(NULL, smar_ctx->smar_cnf.smar_cnf_hostname, l, l); if (NULL == smar_ctx->smar_hostname) { err = sm_error_temp(SM_EM_Q_CONF, ENOMEM); goto error; } } if (smar_ctx->smar_cnf.smar_cnf_dnsbl[0].scdb_name != NULL) SMAR_SET_FLAG(smar_ctx, SMAR_FL_HASDNSBL); if (smar_ctx->smar_cnf.smar_cnf_dns_timeout > 0) { (void) dns_mgr_set_timeout(smar_ctx->smar_dns_mgr_ctx, smar_ctx->smar_cnf.smar_cnf_dns_timeout); } #if 0 /* this create a core dump: see TODO.smi */ cnf_iter = NULL; err = sm_conf_scan_next(smc, "smar.log", sm_log_spec_defs, 0, &cnf_name, &cnf_name_n, NULL, &cnf_iter); SMAR_LEV_DPRINTF(0, (SMAR_DEBFP, "sev=DBG, func=smar_read_cnf, scan_smar.log=%d\n", err)); if (0 == err) #else /* 0 */ /* ** HACK! it should check whether log is in config file ** this only works because facility 0 is KERN. */ if (smar_ctx->smar_cnf.smar_cnf_log.sm_logspc_facility != 0) #endif /* 0 */ { err = sm_log_opensyslog( smar_ctx->smar_cnf.smar_cnf_log.sm_logspc_ident, smar_ctx->smar_cnf.smar_cnf_log.sm_logspc_opt, smar_ctx->smar_cnf.smar_cnf_log.sm_logspc_facility); if (sm_is_err(err)) goto error; err = sm_log_setfp_fd(smar_ctx->smar_lctx, NULL, INVALID_FD); if (sm_is_err(err)) goto error; } ret = sm_dirname(fn, confdir, sizeof(confdir)); if (sm_is_err(ret)) { sm_log_write(smar_ctx->smar_lctx, AR_LCAT_RESOLVER, AR_LMOD_RESOLVER, SM_LOG_ERR, 4, "sev=ERROR, func=smar_read_cnf, fn=%s, sm_dirname=%m" , fn, err); err = ret; goto error; } err = sm_mapconfopen(&smar_ctx->smar_cnf.smar_cnf_mapdecl, smar_ctx->smar_maps, confdir); if (sm_is_err(err)) { sm_log_write(smar_ctx->smar_lctx, AR_LCAT_RESOLVER, AR_LMOD_RESOLVER, SM_LOG_ERR, 4, "sev=ERROR, func=smar_read_cnf, sm_mapconfopen=%m" , err); goto error; } for (us = smar_ctx->smar_cnf.smar_cnf_addr_delim; (uc = *us) != '\0'; us++) { if (!ISPRINT(uc) || uc == '<' || uc == '>' || uc == '@') { err = sm_error_perm(SM_EM_Q_CONF, EINVAL); sm_log_write(smar_ctx->smar_lctx, AR_LCAT_RESOLVER, AR_LMOD_RESOLVER, SM_LOG_ERR, 4, "sev=ERROR, func=smar_read_cnf, address_delimiter=%#x, status=invalid_character" , (int) uc); goto error; } } cnf_iter = NULL; err = sm_conf_scan_next(smc, "smar.greylisting", greycnf_defs, SM_CONF_FLAG_PARSE_ONLY, NULL, NULL, &smar_ctx->smar_cnf.smar_cnf_grey, &cnf_iter); if (0 == err) { ret = sm_greyctl_crt(&smar_ctx->smar_greyctx); if (ret != SM_SUCCESS) { smar_ctx->smar_greyctx = NULL; sm_log_write(smar_ctx->smar_lctx, AR_LCAT_RESOLVER, AR_LMOD_RESOLVER, SM_LOG_ERR, 4, "sev=ERROR, func=smar_read_cnf, sm_greyctl_crt=%m" , ret); } else if (smar_ctx->smar_greyctx != NULL) /* paranoia */ SMAR_SET_FLAG(smar_ctx, SMAR_FL_HASGREY); } cnf_iter = NULL; err = sm_conf_scan_next(smc, "smar.aliases", smar_alias_defs, SM_CONF_FLAG_PARSE_ONLY, NULL, NULL, NULL, &cnf_iter); if (0 == err) SMAR_SET_FLAG(smar_ctx, SMAR_FL_REQALIAS); cnf_iter = NULL; err = sm_conf_scan_next(smc, "smar.access_map", smar_access_defs, SM_CONF_FLAG_PARSE_ONLY, NULL, NULL, NULL, &cnf_iter); if (0 == err) SMAR_SET_FLAG(smar_ctx, SMAR_FL_REQACCESS); else { cnf_iter = NULL; err = sm_conf_scan_next(smc, "smar.dnsbl", smar_dnsbls_defs, SM_CONF_FLAG_PARSE_ONLY, NULL, NULL, NULL, &cnf_iter); if (0 == err) SMAR_SET_FLAG(smar_ctx, SMAR_FL_REQACCESS); } if (psmc != NULL) *psmc = smc; return SM_SUCCESS; error: if (smc != NULL) { sm_conf_destroy(smc); smc = NULL; } return err; } #if STANDALONE static int process(char const *name, FILE *fp) { sm_conf_T *stream; int err; smar_cnf_T s; sm_conf_iterator_T smar_cnf_iter; char const *smar_cnf_name; size_t smar_cnf_name_n; if (((stream = sm_conf_new(name ? name : "*stdin*"))) == NULL) { fprintf(stderr, "error -- sm_conf_new() returns NULL!\n"); return 1; } if ((err = sm_conf_read_FILE(stream, name, fp)) != 0) { char buf[200]; char const *e = NULL; fprintf(stderr, "%.256s: %.256s\n", name ? name : "*stdin*", sm_conf_strerror(err, buf, sizeof buf)); while ((e = sm_conf_syntax_error(stream, e)) != NULL) fprintf(stderr, "%.256s\n", e); sm_conf_destroy(stream); return 2; } smar_cnf_iter = NULL; while ((err = sm_conf_scan_next(stream, "sc", mcp_defs, 0, &smar_cnf_name, &smar_cnf_name_n, &s, &smar_cnf_iter)) == 0) { print_structure(&s, smar_cnf_name, smar_cnf_name_n); } if (err != 0 && err != SM_CONF_ERR_NOT_FOUND) { char buf[200]; char const *e = NULL; fprintf(stderr, "(while scanning) %.256s: %.256s\n", name ? name : "*stdin*", sm_conf_strerror(err, buf, sizeof buf)); while ((e = sm_conf_syntax_error(stream, e)) != NULL) fprintf(stderr, "%.256s\n", e); sm_conf_destroy(stream); return 3; } sm_conf_destroy(stream); return 0; } int main(int ac, char **av) { int ret; int ai; ret = 0; /* make compiler happy */ if (1 == ac) ret = process("*stdin*", stdin); else { for (ai = 1; ai < ac; ai++) { ret = process(av[ai], NULL); if (ret != 0) break; } } return ret; } #endif /* STANDALONE */