/* * 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; }