/* * Copyright (c) 2004-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: smconf.c,v 1.31 2007/06/10 16:14:42 ca Exp $") #include "sm/error.h" #include "sm/assert.h" #include "sm/memops.h" #include "sm/io.h" #include "sm/qmgrcomm.h" #include "sm/sm-conf.h" #include "sm/sm-conf-prt.h" #define SM_QMGRCNFDEF 1 #define SM_SCCNFDEF 1 #define SM_SMARCNFDEF 1 #define SM_MAPCNFDEF 1 #define SM_SSCNFDEF 1 #define SM_CONF_TIME_DEF 1 #define SM_CONF_LOG_DEF 1 #define SM_CONF_BYTE_DEF 1 #define SM_CONF_KBYTE_DEF 1 #define SM_GREYCNFDEF 1 #include "sm/qmgrcnf.h" #include "sm/sccnf.h" #include "sm/mapcnf.h" #include "sm/smarcnf.h" #include "sm/sscnf.h" #include "sm/greycnf.h" #include "sm/qmgrcnfdef.h" #include "sm/sccnfdef.h" #include "sm/mapcnfdef.h" #include "sm/greycnfdef.h" #include "sm/smarcnfdef.h" #include "sm/sscnfdef.h" static int Verbose = 0; static bool Quiet = false; typedef struct sm_cnf_S sm_cnf_T, *sm_cnf_P; struct sm_cnf_S { char *smc_smtpcsock; char *smc_smtpssock; char *smc_smarsock; char *smc_cdb_base; char *smc_hostname; qmgr_cnf_T smc_qmgr_cnf; sc_cnf_T smc_sc_cnf; smar_cnf_T smc_smar_cnf; ss_cnf_T smc_ss_cnf; }; sm_conf_definition_T smx_defs[] = { { SM_CONF_DEF_MAGIC, "SMTPC_socket", sm_conf_type_string, offsetof(sm_cnf_T, smc_smtpcsock), 0, smsmtpcsock, 0, NULL, NULL, NULL, NULL }, { SM_CONF_DEF_MAGIC, "SMTPS_socket", sm_conf_type_string, offsetof(sm_cnf_T, smc_smtpssock), 0, smsmtpssock, 0, NULL, NULL, NULL, NULL }, { SM_CONF_DEF_MAGIC, "SMAR_socket", sm_conf_type_string, offsetof(sm_cnf_T, smc_smarsock), 0, smarsock, 0, NULL, NULL, NULL, NULL }, { SM_CONF_DEF_MAGIC, "CDB_base_directory", sm_conf_type_string, offsetof(sm_cnf_T, smc_cdb_base), 0, "", 0, NULL, NULL, NULL, NULL }, { SM_CONF_DEF_MAGIC, "hostname", sm_conf_type_string, offsetof(sm_cnf_T, smc_hostname), 0, NULL, 0, NULL, NULL, NULL, NULL }, { SM_CONF_DEF_MAGIC, "smar", sm_conf_type_section, offsetof(sm_cnf_T, smc_smar_cnf), 0, /* sizeof(smar_cnf_T), */ NULL, SM_CONF_FLAG_KEEP_DEFAULT, smar_defs, NULL, NULL, NULL }, { SM_CONF_DEF_MAGIC, "smtpc", sm_conf_type_section, offsetof(sm_cnf_T, smc_sc_cnf), 0, /* sizeof(sc_cnf_T), */ NULL, SM_CONF_FLAG_KEEP_DEFAULT|SM_CONF_FLAG_MULTIPLE, sc_defs, NULL, NULL, NULL }, { SM_CONF_DEF_MAGIC, "smtps", sm_conf_type_section, offsetof(sm_cnf_T, smc_ss_cnf), 0, /* sizeof(ss_cnf_T), */ NULL, SM_CONF_FLAG_KEEP_DEFAULT|SM_CONF_FLAG_MULTIPLE, ss_defs, NULL, NULL, NULL }, { SM_CONF_DEF_MAGIC, "qmgr", sm_conf_type_section, offsetof(sm_cnf_T, smc_qmgr_cnf), 0, /* sizeof(qmgr_cnf_T), */ NULL, SM_CONF_FLAG_KEEP_DEFAULT, qmgr_defs, NULL, NULL, NULL }, /* Sentinel */ { SM_CONF_DEF_MAGIC, NULL, 0, 0, 0, NULL, 0, NULL, NULL, NULL, NULL }, }; #define SM_SHOWTREE 0x01 #define SM_SHOWALL 0x02 #define SM_ALLOW_ANY_SECTION 0x04 /* ** SM_READCONF -- Read configuration file ** ** Parameters: ** fn -- filename of configuration file ** flags -- show tree/all? ** name -- name of subsection (can be NULL) ** ** Returns: ** 0 on success, everything else is an error */ static sm_ret_T sm_readconf(const char *fn, uint flags, const char *name) { int err; uint pflags; sm_conf_T *smc; FILE *fp; sm_cnf_T sm_cnf; sm_conf_node_T *root, *node; fp = NULL; sm_memzero(&sm_cnf, sizeof(sm_cnf)); sm_cnf.smc_qmgr_cnf.sm_magic = SM_QMGR_CNF_MAGIC; sm_cnf.smc_sc_cnf.sm_magic = SM_SC_CNF_MAGIC; sm_cnf.smc_smar_cnf.sm_magic = SM_SMAR_CNF_MAGIC; sm_cnf.smc_ss_cnf.sm_magic = SM_SS_CNF_MAGIC; smc = sm_conf_new(fn); if (smc == NULL) { err = errno; sm_io_fprintf(smioerr, "sev=ERROR, func=sm_readconf, file=%s, sm_conf_new=NULL, errno=%d\n", fn, err); return ENOMEM; } err = sm_conf_read_FILE(smc, fn, fp); if (err != 0) { sm_prt_conferr(fn, smc, err, smioerr); sm_conf_destroy(smc); smc = NULL; return err; } pflags = SM_CONF_FLAG_KEEP_DEFAULT; if (SM_IS_FLAG(flags, SM_ALLOW_ANY_SECTION)) pflags |= SM_CONF_FLAG_ALLOW_ANY_SECTION; err = sm_conf_scan(smc, smx_defs, pflags, &sm_cnf); if (err != 0) { sm_prt_conferr(fn, smc, err, smioerr); return err; } else if (Quiet) /* do nothing */ ; else if (SM_IS_FLAG(flags, SM_SHOWTREE)) { root = sm_conf_root(smc); if (root != NULL) { node = root; if (name != NULL) { node = sm_conf_section_next_subsection(smc, root, name, strlen(name), NULL, 0, NULL); } if (node != NULL) { sm_conf_dump_root(smc, node, smioout); sm_io_flush(smioout); } } } else { if (!SM_IS_FLAG(flags, SM_SHOWALL)) sm_io_fprintf(smioout, "QMGR {\n"); qmgr_prt_cnf(&(sm_cnf.smc_qmgr_cnf), smioout, SM_IS_FLAG(flags, SM_SHOWALL)); if (!SM_IS_FLAG(flags, SM_SHOWALL)) sm_io_fprintf(smioout, "}\nSMTPS {\n"); ss_prt_cnf(&(sm_cnf.smc_ss_cnf), smioout, SM_IS_FLAG(flags, SM_SHOWALL)); if (!SM_IS_FLAG(flags, SM_SHOWALL)) sm_io_fprintf(smioout, "}\nSMTPC {\n"); sc_prt_cnf(&(sm_cnf.smc_sc_cnf), smioout, SM_IS_FLAG(flags, SM_SHOWALL)); if (!SM_IS_FLAG(flags, SM_SHOWALL)) sm_io_fprintf(smioout, "}\nSMAR {\n"); smar_prt_cnf(&(sm_cnf.smc_smar_cnf), smioout, SM_IS_FLAG(flags, SM_SHOWALL)); if (!SM_IS_FLAG(flags, SM_SHOWALL)) sm_io_fprintf(smioout, "}\n"); sm_io_flush(smioout); } return SM_SUCCESS; } /* ** USAGE -- Show usage ** ** Parameters: ** prg -- program name ** ** Returns: ** none */ static void usage(const char *prg) { sm_io_fprintf(smioerr, "%s: usage: %s [options] configuration-file\n" "options:\n" "-a show complete configuration data after parsing\n" "-q quiet: do not show configuration file, just perform checks\n" "-s name look for section name\n" "-t show parsed tree\n" "-u do not complain about unknown sections\n" , prg, prg); } /* ** SHOWCOPT -- show compile time options ** ** Parameters: ** none ** ** Returns: ** none */ static void showcopt(void) { sm_io_fprintf(smioout, "compile time options:\n" #if MTA_USE_TLS "MTA_USE_TLS\n" #endif #if MTA_USE_SASL "MTA_USE_SASL\n" #endif #if MTA_USE_PMILTER "MTA_USE_PMILTER\n" #endif #if QMGR_TEST "QMGR_TEST\n" #endif ); sm_io_flush(smioout); } int main(int argc, char **argv) { int ret, ai, r; uint flags; char *name, *prg; prg = argv[0]; ret = 0; /* make compiler happy */ flags = 0; name = NULL; while ((r = getopt(argc, argv, "aqs:tuV")) != -1) { switch (r) { case 'a': flags |= SM_SHOWALL; break; case 'q': Quiet = true; break; case 's': name = optarg; break; case 't': flags |= SM_SHOWTREE; break; case 'u': flags |= SM_ALLOW_ANY_SECTION; break; case 'V': Verbose++; break; default: usage(prg); return 1; } } argc -= optind; argv += optind; if (Verbose == 3) { showcopt(); return 0; } for (ai = 0; ai < argc; ai++) { ret = sm_readconf(argv[ai], flags, name); if (ret != 0) break; } return ret; }