/* This file is part of Mailfromd.
Copyright (C) 2005-2024 Sergey Poznyakoff
Mailfromd is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
Mailfromd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with mailfromd. If not, see <http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <syslog.h>
#include <signal.h>
#include <pwd.h>
#include <grp.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <mailutils/mailutils.h>
#include <mailutils/server.h>
#include <mailutils/syslog.h>
#include <mailutils/cli.h>
#include <mailutils/dbm.h>
#include "mailfromd.h"
#include "callout.h"
#include "srvman.h"
#include "srvcfg.h"
#include "filenames.h"
#include "builtin.h"
#include "prog.h"
/* Configurable options */
int mode = MAILFROMD_DAEMON; /* Default operation mode */
enum smtp_state test_state = smtp_state_envfrom; /* State for --test mode */
int need_script = 1; /* Set if the current mode requires reading the
script file */
char *script_file;
int script_check; /* Check config file syntax and exit */
extern int yy_flex_debug; /* Enable tracing the lexical analyzer */
int script_ydebug; /* Enable tracing the parser */
int script_dump_tree; /* Dump created config tree to stdout */
int script_dump_code; /* Dump disassembled code to stdout */
int script_dump_macros; /* Dump used Sendmail macros */
int script_dump_xref; /* Dump cross-reference */
int preprocess_option; /* Only preprocess the sources */
int location_column_option; /* Print column numbers in error locations */
char *ext_pp_options;
int ext_pp_options_given;
int do_trace; /* Enable tracing configuration */
unsigned optimization_level = 1; /* Optimization level */
int stack_trace_option; /* Print stack traces on runtime errors */
char *main_function_name = "main";
char *callout_server_url;
char *echo_output; /* Output file for 'echo' statements. */
mu_stream_t mf_strecho; /* Output stream for 'echo' statements */
#define ARG_UNSET (-1)
static int trace_option = ARG_UNSET;
static mu_list_t trace_modules;
static char *resolv_conf_file;
/* Preprocessor helper function */
static void
add_pp_option(const char *opt, const char *arg)
{
size_t len;
len = 1 + strlen(opt) + (arg ? strlen(arg) : 0);
if (ext_pp_options) {
len += strlen(ext_pp_options);
ext_pp_options = mu_realloc(ext_pp_options, len + 1);
} else {
ext_pp_options = mu_alloc(len + 1);
ext_pp_options[0] = 0;
}
strcat(ext_pp_options, " ");
strcat(ext_pp_options, opt);
strcat(ext_pp_options, arg);
}
void
pp_define(const char *symbol)
{
add_pp_option("-D", symbol);
}
/* Logging & debugging */
static mu_stream_t mf_trace_stream;
static void
open_trace_stream()
{
int rc = mu_filter_create(&mf_trace_stream,
mf_strecho,
"C-escape",
MU_FILTER_ENCODE,
MU_STREAM_WRITE);
if (rc) {
mu_error(_("cannot create trace stream, "
"using standard log: %s"),
mu_strerror(rc));
mf_trace_stream = mf_strecho;
}
}
void
trace(const char *fmt, ...)
{
if (do_trace) {
int bval = 0;
va_list ap;
if (!mf_trace_stream)
open_trace_stream();
va_start(ap, fmt);
mu_stream_vprintf(mf_trace_stream, fmt, ap);
bval = 1;
mu_stream_ioctl(mf_trace_stream, MU_IOCTL_FILTER,
MU_IOCTL_FILTER_SET_DISABLED,
&bval);
mu_stream_write(mf_trace_stream, "\n", 1, NULL);
bval = 0;
mu_stream_ioctl(mf_trace_stream, MU_IOCTL_FILTER,
MU_IOCTL_FILTER_SET_DISABLED,
&bval);
va_end(ap);
}
}
void
log_status(sfsistat status, SMFICTX *ctx)
{
mu_debug_level_t lev;
mu_debug_category_level(NULL, 0, &lev);
if ((lev & ~MU_DEBUG_LEVEL_MASK(MU_DEBUG_ERROR)) &&
status != SMFIS_CONTINUE) {
const char *str = sfsistat_str(status);
if (str)
logmsg(MU_LOG_INFO,
"%s%s", mailfromd_msgid(ctx), str);
else
logmsg(MU_LOG_INFO,
"%sstatus %d",
mailfromd_msgid(ctx), status);
}
}
/* Sendmail class file support */
static mu_list_t domain_list;
/* Read domains from sendmail-style domain file NAME and store them in
DOMAIN_LIST */
int
read_domain_file(const char *name)
{
FILE *fp;
char buf[256];
char *p;
fp = fopen(name, "r");
if (!fp) {
mu_error(_("cannot open file `%s': %s"),
name, mu_strerror(errno));
return 1;
}
if (!domain_list) {
mu_list_create(&domain_list);
mu_list_set_comparator(domain_list, mf_list_compare_string);
}
while (p = fgets(buf, sizeof buf, fp)) {
char *q;
while (*p && mu_isspace(*p))
p++;
if (*p == '#')
continue;
for (q = p; *q && !mu_isspace(*q); q++)
;
*q = 0;
if (*p == 0)
continue;
mu_list_append(domain_list, strdup(p));
}
fclose(fp);
return 0;
}
/* Return true if we relay domain NAME */
int
relayed_domain_p(char *name)
{
char *p = name;
while (p) {
if (mu_list_locate(domain_list, p, NULL) == 0) {
mu_debug(MF_SOURCE_MAIN, MU_DEBUG_TRACE5,
("%s is in relayed domain %s", name, p));
return 1;
|