/*
 * 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_SSCNFDEF 1

#include "sm/generic.h"
SM_RCSID("@(#)$Id: ssconf.c,v 1.35 2007/06/02 04:25:01 ca Exp $")
#include "sm/error.h"
#include "sm/assert.h"
#include "sm/sysexits.h"
#include "sm/string.h"
#include "sm/io.h"
#include "sm/sm-conf.h"
#include "sm/sm-conf-prt.h"
#include "sm/qmgrcomm.h"
#include "smtps-str.h"
#define SM_LOG_IDENT	"smtps"
#define SM_CONF_LOG_DEF 1
#define SM_CONF_TIME_DEF 1
#define SM_CONF_BYTE_DEF 1
#define SM_CONF_KBYTE_DEF 1
#define SM_SOCKCNFDEF 1
#include "sm/sockcnf.h"
#include "sm/sockcnfdef.h"
#include "smtps.h"
#include "log.h"
#include "sm/sscnf.h"
#include "sm/sscnfdef.h"

/*
**  SS_CHK_CNF -- Check configuration for consistency
**
**	Parameters:
**		ss_ctx -- SMTP Server context
**
**	Returns:
**		usual return code
*/

sm_ret_T
ss_chk_cnf(ss_ctx_P ss_ctx)
{
	sm_ret_T ret;
	ss_cnf_T ssc_cnf;

	ssc_cnf = ss_ctx->ssc_cnf;
	ret = SM_SUCCESS;
	if (ssc_cnf.ss_cnf_r_ta_lim < ssc_cnf.ss_cnf_r_tot_lim) {
		ssc_cnf.ss_cnf_r_ta_lim = ssc_cnf.ss_cnf_r_tot_lim;
		/* complain?? */
	}
	if (SSC_IS_CFLAG(ss_ctx, SSC_CFL_PROTMAP) &&
	    !SSC_IS_CFLAG(ss_ctx, SSC_CFL_PROTBYMAIL|SSC_CFL_PROTBYCLTADDR))
	{
		sm_log_write(ss_ctx->ssc_lctx,
			SS_LCAT_CONFIG, SS_LMOD_CONFIG,
			SM_LOG_ERROR, 6,
			"sev=ERROR, func=ss_chk_cnf, option=%s, requires=%s|%s"
			, SS_PR_CNF, SS_PR_A_SENDER, SS_PR_A_CLTADDR);
		ret = sm_err_perm(EINVAL);
	}
	if (SSC_IS_CFLAG(ss_ctx, SSC_CFL_SE_CONF) &&
		!SSC_IS_CFLAG(ss_ctx, SSC_CFL_ACCESS_DB))
	{
		sm_log_write(ss_ctx->ssc_lctx,
			SS_LCAT_CONFIG, SS_LMOD_CONFIG,
			SM_LOG_WARN, 6,
			"sev=WARN, func=ss_chk_cnf, option=%s, requires=%s, status=turned_on_implicitly"
			, SS_LKP_SE_CONF, SS_CNFN_ACCESS);
		SSC_SET_CFLAG(ss_ctx, SSC_CFL_ACCESS_DB);
	}
	if (SSC_IS_CFLAG(ss_ctx, SSC_CFL_PROTIMPLDET) &&
	    !SSC_IS_CFLAG(ss_ctx, SSC_CFL_PROTMAP))
	{
		sm_log_write(ss_ctx->ssc_lctx,
			SS_LCAT_CONFIG, SS_LMOD_CONFIG,
			SM_LOG_WARN, 6,
			"sev=WARN, func=ss_chk_cnf, option=%s, flag=%s, requires=%s, status=turned_on_implicitly"
			, SS_PR_CNF, SS_IMPLDET, SS_PR_USE_LOOKUP);
		SSC_SET_CFLAG(ss_ctx, SSC_CFL_PROTMAP);
	}
	return ret;
}

/*
**  SS_READ_CNF -- Read configuration file
**
**	Parameters:
**		ss_ctx -- SMTP server context
**		fn -- filename of configuration file
**		psmc -- (pointer to) configuration context (output)
**
**	Returns:
**		0 on success, everything else is an error
*/

sm_ret_T
ss_read_cnf(ss_ctx_P ss_ctx, const char *fn, sm_conf_T **psmc)
{
	int err, i;
	sm_conf_T *smc;
	FILE *fp;
	sm_conf_iterator_T ss_cnf_iter;
	char const *ss_cnf_name;
	size_t ss_cnf_name_n;
	char thissmtps[MAXSECTIONNAME];
	extern int Sk_count;
	extern ss_socket_ctx_T ss_sck_ctx[];

	fp = NULL;
	smc = sm_conf_new(fn);
	if (NULL == smc) {
		err = errno;

		sm_io_fprintf(smioerr, "%s: 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, ss_global_defs, SM_CONF_FLAG_ALLOW_ANY,
			&ss_ctx->ssc_cnf);
	if (err != 0) {
		sm_prt_conferr(fn, smc, err, smioerr);
		goto error;
	}

	ss_cnf_iter = NULL;
	if (ss_ctx->ssc_cnf.ss_cnf_section != NULL)
		sm_snprintf(thissmtps, sizeof(thissmtps), "smtps{%s}",
			ss_ctx->ssc_cnf.ss_cnf_section);
	else
		strlcpy(thissmtps, "smtps", sizeof(thissmtps));
	err = sm_conf_scan_next(smc, thissmtps, ss_defs, 0,
			&ss_cnf_name, &ss_cnf_name_n,
			&ss_ctx->ssc_cnf, &ss_cnf_iter);
	if (err != 0 &&
	    (ss_ctx->ssc_cnf.ss_cnf_section != NULL
	     || err != SM_CONF_ERR_NOT_FOUND))
		sm_prt_conferr(fn, smc, err, smioerr);
	else
		err = 0;

	/*
	**  HACK: transfer configuration data to "global" data
	**  as simple strings which will be parsed later on.
	**  This will go away as soon as the configuration
	**  definition evolves...
	*/

	while (Sk_count < SS_MAX_BIND_ADDRS
	       && ss_ctx->ssc_cnf.ss_cnf_sck_addr[Sk_count] != NULL)
	{
		ss_sck_ctx[Sk_count].sssc_addr =
			ss_ctx->ssc_cnf.ss_cnf_sck_addr[Sk_count];
		++Sk_count;
		++ss_ctx->ssc_cnf.ss_cnf_sk_count;
	}
	if (ss_ctx->ssc_cnf.ss_cnf_relay_to != NULL)
		err = ss_relay_to(ss_ctx, ss_ctx->ssc_cnf.ss_cnf_relay_to);
	if (err == 0 && ss_ctx->ssc_cnf.ss_cnf_relay_from != NULL)
		err = ss_relay_from(ss_ctx, ss_ctx->ssc_cnf.ss_cnf_relay_from);
	if (err != SM_SUCCESS)
		goto error;
	if (ss_ctx->ssc_cnf.ss_cnf_hostname != NULL) {
		size_t l;

		l = strlen(ss_ctx->ssc_cnf.ss_cnf_hostname) + 1;
		ss_ctx->ssc_hostname = sm_str_scpyn0(NULL,
			ss_ctx->ssc_cnf.ss_cnf_hostname, l, l);
		if (NULL == ss_ctx->ssc_hostname) {
			err = sm_error_temp(SM_EM_Q_CONF, ENOMEM);
			goto error;
		}
	}

#if MTA_USE_PMILTER
	/* is a policy_milter socket specified? if yes: set flag */
	if (ss_ctx->ssc_cnf.ss_cnf_miltsockspec.sckspc_type != 0)
		SM_SET_FLAG(ss_ctx->ssc_cnf.ss_cnf_cflags, SSC_CFL_PMILTER);
#endif

#if 0
	err = sm_conf_scan_next(smc, "ss.log",
			ss_defs, 0, &conf_name, &conf_name_n,
			&s, &conf_iter);
#endif
	i = ss_ctx->ssc_cnf.ss_cnf_log.sm_logspc_facility;

	/*
	**  HACK! it should check whether log is in config file
	**  however it's not clear how to do that...
	**  this only works because facility 0 is KERN.
	*/

	if (i != 0) {
		err = sm_log_opensyslog(
			ss_ctx->ssc_cnf.ss_cnf_log.sm_logspc_ident,
			ss_ctx->ssc_cnf.ss_cnf_log.sm_logspc_opt, i);
		if (sm_is_err(err))
			goto error;
		err = sm_log_setfp_fd(ss_ctx->ssc_lctx, NULL, INVALID_FD);
		if (sm_is_err(err))
			goto error;
	}

	(void) ss_chk_cnf(ss_ctx);

	if (psmc != NULL)
		*psmc = smc;

	return err;

  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;
	ss_cnf_T		s;
	sm_conf_iterator_T	qm_cnf_iter;
	char const		*qm_cnf_name;
	size_t			qm_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, "%s: %s\n",
			name ? name : "*stdin*",
			sm_conf_strerror(err, buf, sizeof buf));

		while ((e = sm_conf_syntax_error(stream, e)) != NULL)
			fprintf(stderr, "%s\n", e);

		sm_conf_destroy(stream);
		return 2;
	}

	qm_cnf_iter = NULL;
	while ((err = sm_conf_scan_next(stream, "smtps",
				mcp_defs, 0, &qm_cnf_name, &qm_cnf_name_n,
				&s, &qm_cnf_iter)) == 0)
	{
		print_structure(&s, qm_cnf_name, qm_cnf_name_n);
	}
	if (err != 0 && err != SM_CONF_ERR_NOT_FOUND) {
		char buf[200];
		char const *e = NULL;

		fprintf(stderr, "(while scanning) %s: %s\n",
			name ? name : "*stdin*",
			sm_conf_strerror(err, buf, sizeof buf));

		while ((e = sm_conf_syntax_error(stream, e)) != NULL)
			fprintf(stderr, "%s\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