/*
* 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 */
syntax highlighted by Code2HTML, v. 0.9.1