/*
 * Copyright (c) 2002-2006 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.
 */

#include "sm/generic.h"
SM_RCSID("@(#)$Id: smar_init.c,v 1.79 2007/11/05 05:50:13 ca Exp $")
#include "sm/error.h"
#include "sm/assert.h"
#include "sm/memops.h"
#include "sm/misc.h"
#include "smar.h"
#include "sm/evthr.h"
#include "sm/maps.h"
#include "sm/map.h"
#include "sm/bdb.h"
#include "sm/hostname.h"
#include "sm/qmgrcomm.h"
#include "sm/smardef.h"
#include "sm/confsetpath.h"
#define SMAR_LOG_DEFINES 1
#include "log.h"

/*
 * XREF: See also t-init-0.c: t_smar_0_init() if you change something here!
 */

/*
**  SMAR_INIT0 -- initialize SMAR (before reading configuration)
**
**	Parameters:
**		smar_ctx -- SMAR context
**
**	Returns:
**		usual sm_error code
*/

sm_ret_T
smar_init0(smar_ctx_P smar_ctx)
{
	int r;
	sm_ret_T ret;
#if SMAR_USE_DNS
	dns_mgr_ctx_P dns_mgr_ctx;
#endif

	/* should we allocate the context here? */
	SM_REQUIRE(smar_ctx != NULL);

	/* clear out data */
	sm_memzero(smar_ctx, sizeof(*smar_ctx));

	/*
	 *  needs to be set here because it's checked in smar_stop()
	 *  which can be invoked rather "directly" on error.
	 */
	smar_ctx->sm_magic = SM_SMAR_CTX_MAGIC;

	/* set default values */
	smar_ctx->smar_cnf.smar_cnf_loglevel = SM_LOG_LEVEL;
	smar_ctx->smar_cnf.smar_cnf_addr_delim = SM_ADDR_DELIM;

	smar_ctx->smar_cnf.smar_cnf_minthr = SMAR_CNF_MINTHR;
	smar_ctx->smar_cnf.smar_cnf_maxthr = SMAR_CNF_MAXTHR;
	smar_ctx->smar_cnf.smar_cnf_maxfd = SMAR_CNF_MAXFD;
	smar_ctx->smar_max_thrds_s = SMAR_CNF_MAXTHR;
	smar_ctx->smar_max_thrds_h = SMAR_CNF_MAXTHR * 2;

	smar_ctx->smar_cnf.smar_cnf_alias_fl = SMARCNF_FL_MAP_LP
				|SMARCNF_FL_MAP_DETPLUS
				|SMARCNF_FL_MAP_DETSTAR
				|SMARCNF_FL_MAP_STAR
				|SMARCNF_FL_MAP_FULL
				;
	smar_ctx->smar_alias_lfl = SMMAP_LFL_ALIAS;

	smar_ctx->smar_cnf.smar_cnf_lum_fl = SMARCNF_FL_MAP_LP
				|SMARCNF_FL_MAP_DETPLUS
				|SMARCNF_FL_MAP_DETSTAR
				|SMARCNF_FL_MAP_STAR
				|SMARCNF_FL_MAP_DOTSUBDOM
				|SMARCNF_FL_MAP_FULL
				;
	smar_ctx->smar_lum_lfl = SMMAP_LFL_ALIAS;

	smar_ctx->smar_cnf.smar_cnf_mt_fl = SMARCNF_FL_MAP_DOMAIN
				|SMARCNF_FL_MAP_DOTSUBDOM
				|SMARCNF_FL_MAP_DOT
				;
	smar_ctx->smar_mt_lfl = SMMAP_LFL_MT;

	smar_ctx->smar_cnf.smar_cnf_dns_flags = DNS_USE_RSLVCNF;

	if (NULL == smar_ctx->smar_hostname) {
		ret = sm_myhostname(&smar_ctx->smar_hostname);
		if (sm_is_err(ret)) {
			sm_io_fprintf(smioerr,
				"sev=ERROR, func=smar_init, sm_myhostname=%m\n"
				, ret);
			goto error;
		}
	}

	ret =  sm_bdbversionok();
	if (sm_is_err(ret)) goto error;
	smar_ctx->smar_cnf.smar_cnf_sock = smarsock;

	ret = sm_maps_init(&smar_ctx->smar_maps);
	if (NULL == smar_ctx->smar_maps) {
		ret = sm_error_temp(SM_EM_AR, ENOMEM);
		goto error;
	}
	ret = sm_maps_create(smar_ctx->smar_maps);
	if (sm_is_err(ret)) goto error;

#if SMAR_USE_DNS
	dns_mgr_ctx = NULL;
	ret = dns_rslv_new(41);
	if (sm_is_err(ret)) goto error;
	ret = dns_mgr_ctx_new(0, DNS_TIMEOUT, DNS_MGR_HTSIZE, DNS_MGR_HTMAX,
			&dns_mgr_ctx);
	if (sm_is_err(ret)) goto error;
	dns_mgr_ctx->dnsmgr_lctx = smar_ctx->smar_lctx;
	smar_ctx->smar_dns_mgr_ctx = dns_mgr_ctx;
	smar_ctx->smar_nameserveripv4s[0] = (ipv4_T) htonl(LOCALHOST_IP);
	smar_ctx->smar_dns_ntsks = 0;
#endif /* SMAR_USE_DNS */

	ret = thr_init();
	if (sm_is_err(ret)) goto err1;

	r = pthread_mutex_init(&smar_ctx->smar_mutex, SM_PTHREAD_MUTEXATTR);
	if (r != 0) {
		ret = sm_error_perm(SM_EM_AR, r);
		goto err2;
	}

	smar_ctx->smar_cnf.sm_magic = SM_SMAR_CNF_MAGIC;
#if 0
	ret = sm_rcbcom_open(&smar_ctx->smar_qmgr_com);
	if (sm_is_err(ret)) goto err3;
#endif /* 0 */

	for (r = 0; r < SMAR_MAX_CLTS; r++)
	{
		ret = smar_clt_new(smar_ctx, &(smar_ctx->smar_clt_ctx[r]));
		if (sm_is_err(ret)) goto err3;
	}

	ret = sm_log_create(NULL, &smar_ctx->smar_lctx, NULL);
	if (sm_is_err(ret)) goto err4;
	ret = sm_log_setfp_fd(smar_ctx->smar_lctx, smiolog, SMIOLOG_FILENO);
	if (sm_is_err(ret)) goto err5;
	ret = sm_log_setdebuglevel(smar_ctx->smar_lctx, smar_ctx->smar_cnf.smar_cnf_loglevel);
	if (sm_is_err(ret)) goto err5;
#if SMAR_USE_DNS
	/* HACK this shouldn't access the structure directly */
	dns_mgr_ctx->dnsmgr_lctx = smar_ctx->smar_lctx;
#endif

	smar_ctx->smar_status = SMAR_ST_INIT;
	return SM_SUCCESS;

  err5:
	(void) sm_log_destroy(smar_ctx->smar_lctx);
  err4:
  err3:
	(void) pthread_mutex_destroy(&smar_ctx->smar_mutex);
  err2:
	(void) thr_stop();
  err1:
#if SMAR_USE_DNS
	if (dns_mgr_ctx != NULL)
		dns_mgr_ctx_del(dns_mgr_ctx);
	smar_ctx->smar_dns_mgr_ctx = NULL;
#endif /* SMAR_USE_DNS */
  error:
	if (smar_ctx->smar_maps != NULL) {
		(void) sm_maps_term(smar_ctx->smar_maps);
		smar_ctx->smar_maps = NULL;
	}
	smar_ctx->sm_magic = SM_MAGIC_NULL;
	smar_ctx->smar_cnf.sm_magic = SM_MAGIC_NULL;
	return ret;
}

/*
**  SMAR_INIT1 -- initialize SMAR (after reading configuration)
**
**	Parameters:
**		smar_ctx -- SMAR context
**
**	Returns:
**		usual sm_error code
*/

sm_ret_T
smar_init1(smar_ctx_P smar_ctx)
{
	sm_ret_T ret;
	sm_cstr_P mtype, mname;
	const char *mpath;
	char confdir[PATH_MAX];

	SM_REQUIRE(smar_ctx != NULL);
	mtype = mname = NULL;
	ret = sm_log_setdebuglevel(smar_ctx->smar_lctx,
			smar_ctx->smar_cnf.smar_cnf_loglevel);

	ret = sm_dirname(smar_ctx->smar_cnf.smar_cnf_conffile, confdir,
			sizeof(confdir));
	if (sm_is_err(ret)) goto error;

	if (smar_ctx->smar_cnf.smar_cnf_lum_name != NULL) {
		ret = sm_mapname_findc(smar_ctx->smar_maps,
				smar_ctx->smar_cnf.smar_cnf_lum_name,
				&smar_ctx->smar_lum);
		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_init1, local_user_map_name=%.256s, open_local_user_map=%m"
				, smar_ctx->smar_cnf.smar_cnf_lum_name, ret);
			smar_ctx->smar_lum = NULL;
			goto error;
		}
	}

	ret = sm_gen_conf_path(smar_ctx->smar_cnf.smar_cnf_cdb_base,
		smar_ctx->smar_cnf.smar_cnf_sock, smarsock,
		&smar_ctx->smar_cnf.smar_cnf_sock_abs, NULL);
	if (sm_is_err(ret))
		goto error;

	if (smar_ctx->smar_cnf.smar_cnf_mt_name != NULL) {
		ret = sm_mapname_findc(smar_ctx->smar_maps,
				smar_ctx->smar_cnf.smar_cnf_mt_name,
				&smar_ctx->smar_mt_map);
		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_init1, mt_name=%.256s, open_map=%m"
				, smar_ctx->smar_cnf.smar_cnf_mt_name, ret);
			smar_ctx->smar_mt_map = NULL;
			goto error;
		}
	}
	else {
		mtype = sm_cstr_scpyn0((const uchar *)SMAR_MT_TYPE, strlen(SMAR_MT_TYPE));
		if (NULL == mtype) {
			ret = sm_error_temp(SM_EM_AR, ENOMEM);
			goto error;
		}
		mname = sm_cstr_scpyn0((const uchar *)SMAR_MT_NAME, strlen(SMAR_MT_NAME));
		if (NULL == mname) {
			ret = sm_error_temp(SM_EM_AR, ENOMEM);
			goto error;
		}
		smar_ctx->smar_mt_map = NULL;
		ret = sm_map_open(smar_ctx->smar_maps, mname, mtype, 0, NULL
				, SMAP_MODE_RDONLY, &smar_ctx->smar_mt_map
				, SMPO_HASH_NELEM, 1023, SMPO_MAX_ELEM, 0
				, SMPO_INIT_CB, smar_mt_init, smar_ctx
				, SMPO_END);
		if (sm_is_err(ret)) {
			sm_log_write(smar_ctx->smar_lctx,
				AR_LCAT_INIT, AR_LMOD_CONFIG, SM_LOG_ERROR, 0,
				"sev=ERROR, func=smar_init1, sm_map_open=%m, map=%C, type=%C"
				, ret, mname, mtype);
			smar_ctx->smar_mt_map = NULL;
			goto error;
		}
		SM_CSTR_FREE(mname);
		SM_CSTR_FREE(mtype);
	}

	/* aliases */
	if (smar_ctx->smar_cnf.smar_cnf_alias_name != NULL) {
		ret = sm_mapname_findc(smar_ctx->smar_maps,
				smar_ctx->smar_cnf.smar_cnf_alias_name,
				&smar_ctx->smar_aliases);
		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_init1, aliases_name=%.256s, find_map=%m"
				, smar_ctx->smar_cnf.smar_cnf_alias_name, ret);
			smar_ctx->smar_aliases = NULL;
			goto error;
		}
		SMAR_SET_FLAG(smar_ctx, SMAR_FL_HASALIAS);
	}
	else {
		mtype = sm_cstr_scpyn0((const uchar *)SMAR_ALIASES_TYPE, strlen(SMAR_ALIASES_TYPE));
		if (NULL == mtype) {
			ret = sm_error_temp(SM_EM_AR, ENOMEM);
			goto error;
		}
		mname = sm_cstr_scpyn0((const uchar *)SMAR_ALIASES_NAME, strlen(SMAR_ALIASES_NAME));
		if (NULL == mname) {
			ret = sm_error_temp(SM_EM_AR, ENOMEM);
			goto error;
		}
		SM_GEN_MAP_PATH(mpath, smar_ctx->smar_cnf.smar_cnf_alias_path,
			confdir, smar_ctx->smar_cnf.smar_cnf_alias_fn,
			SMAR_ALIASES_FILE, error);
		smar_ctx->smar_aliases = NULL;
		ret = sm_map_open(smar_ctx->smar_maps, mname, mtype, 0,
				mpath, SMAP_MODE_RDONLY,
				&smar_ctx->smar_aliases, SMPO_END);
		SM_CSTR_FREE(mname);
		SM_CSTR_FREE(mtype);

		if (sm_is_err(ret)) {
			bool required;

			required = SMAR_IS_FLAG(smar_ctx, SMAR_FL_REQALIAS);
			sm_log_write(smar_ctx->smar_lctx,
				AR_LCAT_INIT, AR_LMOD_CONFIG,
				required ? SM_LOG_ERROR : SM_LOG_WARN, 3,
				"sev=%s, func=smar_init1, map=%s, type=%s, open=%m"
				, required ? "ERROR" : "WARN"
				, mpath, SMAR_ALIASES_TYPE, ret);
			smar_ctx->smar_aliases = NULL;
			if (required)
				goto error;
			ret = SM_SUCCESS;
		}
		else
			SMAR_SET_FLAG(smar_ctx, SMAR_FL_HASALIAS);
	}

	/* access map */
	if (smar_ctx->smar_cnf.smar_cnf_access_name != NULL) {
		ret = sm_mapname_findc(smar_ctx->smar_maps,
				smar_ctx->smar_cnf.smar_cnf_access_name,
				&smar_ctx->smar_access);
		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_init1, access_name=%.256s, find_map=%m"
				, smar_ctx->smar_cnf.smar_cnf_access_name, ret);
			smar_ctx->smar_access = NULL;
			goto error;
		}
		SMAR_SET_FLAG(smar_ctx, SMAR_FL_HASACCESS);
	}
	else {
		mtype = sm_cstr_scpyn0((const uchar *)SMAR_ACCESS_TYPE, strlen(SMAR_ACCESS_TYPE));
		if (NULL == mtype) {
			ret = sm_error_temp(SM_EM_AR, ENOMEM);
			goto error;
		}
		mname = sm_cstr_scpyn0((const uchar *)SMAR_ACCESS_NAME, strlen(SMAR_ACCESS_NAME));
		if (NULL == mname) {
			ret = sm_error_temp(SM_EM_AR, ENOMEM);
			goto error;
		}
		SM_GEN_MAP_PATH(mpath, smar_ctx->smar_cnf.smar_cnf_access_path,
			confdir, smar_ctx->smar_cnf.smar_cnf_access_fn,
			SMAR_ACCESS_FILE, error);
		smar_ctx->smar_access = NULL;
		ret = sm_map_open(smar_ctx->smar_maps, mname, mtype, 0,
				mpath, SMAP_MODE_RDONLY,
				&smar_ctx->smar_access, SMPO_END);
		SM_CSTR_FREE(mname);
		SM_CSTR_FREE(mtype);

		if (sm_is_err(ret)) {
			smar_ctx->smar_access = NULL;
			if (SMAR_IS_FLAG(smar_ctx, SMAR_FL_REQACCESS)) {
				sm_log_write(smar_ctx->smar_lctx,
					AR_LCAT_INIT, AR_LMOD_CONFIG,
					SM_LOG_ERROR, 3,
					"sev=ERROR, func=smar_init1, map=%s, type=%s, open=%m"
					, mpath, SMAR_ACCESS_TYPE, ret);
				goto error;
			}
			ret = SM_SUCCESS;
		}
		else
			SMAR_SET_FLAG(smar_ctx, SMAR_FL_HASACCESS);
	}

#define MAPC_STYPE	"strmap"

	mtype = sm_cstr_scpyn0((const uchar *)MAPC_STYPE, strlen(MAPC_STYPE));
	if (NULL == mtype) {
		ret = sm_error_temp(SM_EM_AR, ENOMEM);
		goto error;
	}
	smar_ctx->smar_strmaptype = mtype;
	mtype = NULL;

	ret = smar_init_map_lfl(smar_ctx, smar_ctx->smar_cnf.smar_cnf_alias_fl,
				&smar_ctx->smar_alias_lfl);
	if (sm_is_err(ret)) goto error;

	ret = smar_init_map_lfl(smar_ctx, smar_ctx->smar_cnf.smar_cnf_lum_fl,
				&smar_ctx->smar_lum_lfl);
	if (sm_is_err(ret)) goto error;

	ret = smar_init_map_lfl(smar_ctx, smar_ctx->smar_cnf.smar_cnf_mt_fl,
				&smar_ctx->smar_mt_lfl);
	if (sm_is_err(ret)) goto error;

#if SMAR_USE_DNS
	smar_ctx->smar_dns_mgr_ctx->dnsmgr_retries =
				smar_ctx->smar_cnf.smar_cnf_dns_retries;
#endif

	/* initialize event threads system */
	smar_ctx->smar_max_thrds_s = smar_ctx->smar_cnf.smar_cnf_maxthr;
	smar_ctx->smar_max_thrds_h = smar_ctx->smar_max_thrds_s * 2;
	if (smar_ctx->smar_max_thrds_s > smar_ctx->smar_max_thrds_h)
		smar_ctx->smar_max_thrds_h = UINT_MAX;
	ret = evthr_init(&smar_ctx->smar_ev_ctx,
		smar_ctx->smar_cnf.smar_cnf_minthr,
		smar_ctx->smar_max_thrds_s,
		smar_ctx->smar_cnf.smar_cnf_maxfd);
	if (sm_is_err(ret)) goto error;
	ret = evthr_set_max_h(smar_ctx->smar_ev_ctx, smar_ctx->smar_max_thrds_h);
	if (sm_is_err(ret)) goto error;
#if SMAR_DEBUG
	evthr_set_dbglvl(smar_ctx->smar_ev_ctx, smar_debug);
#endif

	if (smar_ctx->smar_greyctx != NULL) {
		ret = sm_greyctl_open(smar_ctx->smar_greyctx, &smar_ctx->smar_cnf.smar_cnf_grey);
		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_init1, sm_greyctl_open=%m"
				, ret);
			goto error;
		}
	}

	return ret;

  error:
	SM_CSTR_FREE(mname);
	SM_CSTR_FREE(mtype);
	return ret;
}


syntax highlighted by Code2HTML, v. 0.9.1