/*
* 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_rdcf.c,v 1.80 2007/11/10 04:03:58 ca Exp $")
#include "sm/common.h"
#include "sm/error.h"
#include "sm/assert.h"
#include "sm/ctype.h"
#include "sm/io.h"
#include "sm/net.h"
#include "sm/mapc.h"
#include "sm/bdb.h"
#include "sm/version.h"
#include "smar.h"
#include "log.h"
#include "sm/sysexits.h"
#include "sm/sm-conf.h"
#include "sm/sm-conf-prt.h"
#include "sm/smarcnfdef.h"
/*
** SMAR_SHOWCOPT -- show compile time options
**
** Parameters:
** smar_ctx -- SMAR context
**
** Returns:
** none
*/
static void
smar_showcopt(smar_ctx_P smar_ctx)
{
sm_io_fprintf(smioout, "compile time options:\n"
#if RCBCOMM_DEBUG
"RCBCOMM_DEBUG\n"
#endif
#if SMAR_DEBUG
"SMAR_DEBUG\n"
#endif
#if SMAR_RVRS_ALL
"SMAR_RVRS_ALL\n"
#endif
#if SMAR_TEST
"SMAR_TEST\n"
#endif
#if SMAR_USE_DNS
"SMAR_USE_DNS\n"
#endif
#if MTA_LIBDNS_TEST
"MTA_LIBDNS_TEST\n"
#endif
);
sm_io_flush(smioout);
}
/*
** SMAR_SHOWVERSION -- show version information
**
** Parameters:
** smar_ctx -- SMAR context
** progname -- program name
** cnf -- configuration file name
** level -- how much detail?
**
** Returns:
** none
*/
static sm_ret_T
smar_showversion(smar_ctx_P smar_ctx, const char *progname, const char *cnf, uint level)
{
char *prefix;
prefix = "";
if (level >= SM_SV_RD_CONF)
prefix = "# ";
sm_io_fprintf(smioout, "%s%s: %s\n", prefix, progname, MTA_VERSION_STR);
if (SM_SHOW_VERSION(level))
sm_io_fprintf(smioout, "%sversion=0x%08x\n",
prefix, MTA_VERSION);
if (SM_SHOW_LIBS(level))
(void) sm_bdbversionprt(smioout);
if (SM_SHOW_OPTIONS(level))
smar_showcopt(smar_ctx);
if (SM_SHOW_RD_CONF(level) && cnf != NULL && *cnf != '\0') {
sm_io_fprintf(smioout,
"# configuration-file=%s\n\n", cnf);
(void) sm_conf_prt_conf(smar_global_defs,
&smar_ctx->smar_cnf, smioout);
}
else if (SM_SHOW_DFLT_CONF(level)) {
sm_io_fprintf(smioout, "# default configuration:\n\n");
(void) sm_conf_prt_dflt(smar_global_defs, 0, smioout);
}
else if (SM_SHOW_ALL_CONF(level)) {
sm_io_fprintf(smioout,
"# configuration including flags.\n"
"# note: this data cannot be used as configuration file\n"
"# but it shows the available flags.\n"
);
(void) sm_conf_prt_dflt(smar_global_defs, SMC_FLD_FLAGS,
smioout);
}
sm_io_flush(smioout);
return sm_error_perm(SM_EM_AR, SM_E_DONTSTART);
}
/*
** SMAR_USAGE -- usage message
**
** Parameters:
** smar_ctx -- SMAR context
**
** Returns:
** usual sm_error code
*/
static sm_ret_T
smar_usage(smar_ctx_P smar_ctx)
{
sm_io_fprintf(smioerr, "usage: smar [options]\n"
"%s address resolver\n"
"-A flags Set aliases flags (localpart, localdomain, all)\n"
"-D Print compile time options\n"
#if SMAR_DEBUG
"-d n Debug level\n"
#endif
"-f name Name of configuration file [none]\n"
#if SM_HEAP_CHECK
"-H n Heap check level\n"
#endif
"-i IPv4 Use IPv4 address for name server [127.0.0.1]\n"
" (up to %u can be specified)\n"
"-O n DNS query timeout [%ds]\n"
#if SMAR_TEST
"-R n Cause a resolver error if random() < n\n"
#endif
"-r Do not read /etc/resolv.conf\n"
"-S a=name Socket for client communication (QMGR/SMTPS) [%s]\n"
"-T Use TCP for DNS queries instead of UDP\n"
"-U Use connect(2) for UDP\n"
"-v n Loglevel\n"
"-V Show version information (can be specified multiple times)\n"
, MTA_VERSION_STR
, SM_DNS_MAX_TSKS /* -i */
, DNS_TIMEOUT /* -O */
, smar_ctx->smar_cnf.smar_cnf_sock
);
return sm_error_perm(SM_EM_AR, SM_E_USAGE);
}
/*
** SMAR_RDCF -- read configuration
**
** Parameters:
** smar_ctx -- SMAR context
** argc -- number of arguments
** argv -- vector of arguments
**
** Returns:
** usual sm_error code
*/
static sm_ret_T
smar_rd_resolv_conf(smar_ctx_P smar_ctx)
{
uint ui;
char buf[64], *cp;
FILE *fp;
#define MATCH(line, name) \
(!strncmp(line, name, sizeof(name) - 1) && \
(line[sizeof(name) - 1] == ' ' || \
line[sizeof(name) - 1] == '\t'))
if ((fp = fopen("/etc/resolv.conf", "r")) != NULL) {
while (fgets(buf, sizeof(buf), fp) != NULL) {
if ((ui = smar_ctx->smar_dns_ntsks) < SM_DNS_MAX_TSKS &&
MATCH(buf, "nameserver"))
{
cp = buf + sizeof("nameserver") - 1;
while (*cp == ' ' || *cp == '\t')
cp++;
/* NO error checks! */
smar_ctx->smar_nameserveripv4s[ui] = (ipv4_T) inet_addr(cp);
++smar_ctx->smar_dns_ntsks;
}
}
(void) fclose(fp);
}
return SM_SUCCESS;
}
/*
** SMAR_RDCF -- read configuration
**
** Parameters:
** smar_ctx -- SMAR context
** argc -- number of arguments
** argv -- vector of arguments
**
** Returns:
** usual sm_error code
*/
sm_ret_T
smar_rdcf(smar_ctx_P smar_ctx, int argc, char *argv[])
{
int c, list_mapc;
uint ui, showversion;
sm_ret_T ret;
char *s;
SM_IS_SMAR_CTX(smar_ctx);
showversion = 0;
list_mapc = -1;
ret = SM_SUCCESS;
while ((c = getopt(argc, argv, "A:Dd:f:H:hi:l:O:R:r:S:TUv:V?")) != -1
&& ret == SM_SUCCESS)
{
switch (c) {
case 'A':
smar_ctx->smar_cnf.smar_cnf_alias_fl = strtoul(optarg, NULL, 0);
break;
case 'D':
smar_showcopt(smar_ctx);
ret = sm_error_info(SM_EM_AR, SM_E_DONTSTART);
break;
case 'd':
ui = (uint) atoi(optarg);
#if SMAR_DEBUG
smar_debug = ui;
#endif
#if RCBCOMM_DEBUG
rcbcomm_debug = ui;
#endif
break;
case 'f':
s = strdup(optarg);
if (NULL == s) {
sm_io_fprintf(smioerr,
"sev=ERROR, func=smar_rdcf, argument=\"%@s\", strdup=%m\n"
, optarg, sm_err_temp(errno));
ret = sm_error_perm(SM_EM_Q_START, EX_OSERR);
break;
}
smar_ctx->smar_cnf.smar_cnf_conffile = s;
ret = smar_read_cnf(smar_ctx, s, &smar_ctx->smar_cnf.smar_cnf_smc);
if (sm_is_err(ret)) {
sm_io_fprintf(smioerr,
"sev=ERROR, func=smar_rdcf, status=invalid_configuration_file, error=%m\n"
, ret);
}
break;
case 'H':
#if SM_HEAP_CHECK
SmHeapCheck = atoi(optarg);
#endif
break;
case 'i':
#if SMAR_USE_DNS
if ((ui = smar_ctx->smar_dns_ntsks) < SM_DNS_MAX_TSKS) {
smar_ctx->smar_nameserveripv4s[ui] = (ipv4_T) inet_addr(optarg);
++smar_ctx->smar_dns_ntsks;
}
else {
sm_io_fprintf(smioerr,
"sev=ERROR, func=smar_rdcf, status=too many nameservers, max=%u\n"
, SM_DNS_MAX_TSKS);
ret = smar_usage(smar_ctx);
}
#endif /* SMAR_USE_DNS */
break;
case 'l':
list_mapc = (int) strtol(optarg, NULL, 0);
break;
case 'O':
ui = (uint) atoi(optarg);
ret = dns_mgr_set_timeout(smar_ctx->smar_dns_mgr_ctx,
ui);
break;
case 'R':
#if SMAR_TEST
smar_ctx->smar_rand_err = atol(optarg);
#endif
break;
case 'r':
smar_ctx->smar_cnf.smar_cnf_dns_flags &= ~DNS_USE_RSLVCNF;
break;
case 'S':
if (optarg != NULL && ISALPHA(optarg[0])
&& optarg[1] == '=' && optarg[2] != '\0')
ui = 2;
else {
ret = smar_usage(smar_ctx);
break;
}
s = NULL;
switch (optarg[0]) {
case 'a':
s = strdup(optarg + ui);
if (NULL == s) {
sm_io_fprintf(smioerr,
"sev=ERROR, func=smar_rdcf, argument=\"%@s\", strdup=%m\n"
, optarg + ui
, sm_err_temp(errno));
ret = sm_error_perm(SM_EM_Q_START,
EX_OSERR);
}
break;
default:
ret = smar_usage(smar_ctx);
break;
}
switch (optarg[0]) {
case 'a':
smar_ctx->smar_cnf.smar_cnf_sock = s;
break;
default:
ret = smar_usage(smar_ctx);
break;
}
s = NULL;
break;
case 'T':
smar_ctx->smar_cnf.smar_cnf_dns_flags |= DNS_TSK_FL_USETCP;
break;
case 'U':
smar_ctx->smar_cnf.smar_cnf_dns_flags |= DNS_TSK_FL_CONNECTUDP;
break;
case 'v':
smar_ctx->smar_cnf.smar_cnf_loglevel =
(uint) atoi(optarg);
break;
case 'V':
++showversion;
break;
case 'h':
case '?':
default:
ret = smar_usage(smar_ctx);
break;
}
}
if (sm_is_err(ret))
goto error;
if (showversion > 0) {
ret = smar_showversion(smar_ctx, argv[0],
smar_ctx->smar_cnf.smar_cnf_conffile, showversion);
goto error;
}
if (list_mapc >= 0) {
sm_maps_P maps;
maps = NULL;
ret = sm_maps_init(&maps);
if (sm_is_err(ret))
goto error;
if (NULL == maps) {
ret = sm_error_perm(SM_EM_AR, SM_E_DONTSTART);
goto error;
}
ret = sm_maps_create(maps);
if (sm_is_err(ret))
goto error;
c = sm_mapc_list(smioout, maps, list_mapc, 0);
ret = sm_error_perm(SM_EM_AR, SM_E_DONTSTART);
goto error;
}
if (0 == smar_ctx->smar_dns_ntsks) {
if (SM_IS_FLAG(smar_ctx->smar_cnf.smar_cnf_dns_flags, DNS_USE_RSLVCNF))
(void) smar_rd_resolv_conf(smar_ctx);
else {
smar_ctx->smar_nameserveripv4s[0] = (ipv4_T) htonl(LOCALHOST_IP);
smar_ctx->smar_dns_ntsks = 1;
}
}
smar_ctx->smar_status = SMAR_ST_CONF;
return SM_SUCCESS;
error:
return ret;
}
syntax highlighted by Code2HTML, v. 0.9.1