summaryrefslogtreecommitdiffabout
path: root/src/main.c
authorSergey Poznyakoff <gray@gnu.org.ua>2008-02-10 14:08:36 (GMT)
committer Sergey Poznyakoff <gray@gnu.org.ua>2008-02-10 14:08:36 (GMT)
commita1871918823166cac9f0c12164ba27cb3b1f0c2c (patch) (side-by-side diff)
tree7260d118aa5af6a8f006f9b2dac6cabde782db8c /src/main.c
parent455b645247bdc0f01239b2352a9d8f07f446024f (diff)
downloadmailfromd-a1871918823166cac9f0c12164ba27cb3b1f0c2c.tar.gz
mailfromd-a1871918823166cac9f0c12164ba27cb3b1f0c2c.tar.bz2
Merged HEAD from branches/gmach
git-svn-id: file:///svnroot/mailfromd/trunk@1612 7a8a7f39-df28-0410-adc6-e0d955640f24
Diffstat (limited to 'src/main.c') (more/less context) (ignore whitespace changes)
-rw-r--r--src/main.c2244
1 files changed, 0 insertions, 2244 deletions
diff --git a/src/main.c b/src/main.c
deleted file mode 100644
index 416916b..0000000
--- a/src/main.c
+++ b/dev/null
@@ -1,2244 +0,0 @@
-/* This file is part of mailfromd.
- Copyright (C) 2005, 2006, 2007, 2008 Sergey Poznyakoff
-
- This program 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.
-
- This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#define MF_SOURCE_NAME MF_SOURCE_MAIN
-
-#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>
-#ifdef HAVE_LOCALE_H
-# include <locale.h>
-#endif
-
-#include <mailutils/mailutils.h>
-#if MAILUTILS_VERSION_NUMBER < 1290
-# include <mailutils/argp.h>
-#else
-# include <mailutils/libargp.h>
-#endif
-#ifdef HAVE_MAILUTILS_SYSLOG_H
-# include <mailutils/syslog.h>
-#endif
-#include "mailfromd.h"
-
-
-/* Configurable options */
-
-int mode = MAILFROMD_DAEMON; /* Default operation mode */
-enum smtp_state test_state = smtp_state_envfrom; /* State for --test mode */
-int need_config = 1;/* Set if the current mode requires reading the
- configuration file */
-char *script_file = DEFAULT_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 */
-
-#ifdef DEFAULT_PREPROCESSOR
-# define DEF_EXT_PP DEFAULT_PREPROCESSOR
-#else
-# define DEF_EXT_PP NULL
-#endif
-char *ext_pp = DEF_EXT_PP; /* External preprocessor to use */
-
-int do_transcript; /* Enable session transript */
-int do_trace; /* Enable tracing configuration */
-int mtasim_option; /* mtasim compatibility mode */
-unsigned optimization_level = 1; /* Optimization level */
-int log_to_stderr; /* Use stderr for logging */
-char *portspec; /* Communication socket specification.
- See init_names() */
-int force_remove; /* Remove local communication socket if it already
- exists */
-int foreground; /* Stay in foreground */
-int single_process_option; /* Run in single process mode. */
-unsigned long source_address = INADDR_ANY; /* Source address for TCP
- connections */
-#ifdef USE_SYSLOG_ASYNC
-int use_syslog_async = DEFAULT_SYSLOG_ASYNC;
- /* Use asynchronous syslog implementation */
-#endif
-
-char *syslog_tag; /* Tag to mark syslog entries with. */
-char *mailfromd_state_dir; /* see init_names() */
-char *pidfile; /* see init_names() */
-char *user = DEFAULT_USER; /* Switch to this user privileges after
- startup */
-mu_list_t retain_groups; /* List of group IDs to retain when switching
- to users privileges. */
-
-/* DBM-related options */
-time_t negative_expire_interval = DEFAULT_EXPIRE_INTERVAL/2;
- /* Expire negative cache entries after this
- number of seconds */
-time_t expire_interval = 0; /* When set, overrides all the three above
- intervals */
-int predict_next_option;
-double predict_rate; /* Prediction rate for --list --format=rates*/
-
-int ignore_failed_reads_option; /* Ignore failed reads while compacting or
- expiring */
-int all_option; /* Process all databases */
-char *time_format_string = "%c"; /* String to format the time stamps */
-size_t lock_retry_count_option = 3;
-time_t lock_retry_timeout_option = 1;
-/* DBM-related options end */
-
-int source_info_option; /* Debug messages include source locations */
-int stack_trace_option; /* Print stack traces on runtime errors */
-char *file_option; /* File name for DB management commands */
-struct db_format *format_option;
-
-/* Connect settings */
-time_t connect_timeout = 10;
-
-/* I/O settings */
-time_t io_timeout = 3;
-
-/* Initial response settings */
-time_t response_timeout = 30;
-
-
-/* Logging & debugging */
-
-int
-syslog_printer (int prio, const char *fmt, va_list ap)
-{
-#ifdef USE_SYSLOG_ASYNC
- if (use_syslog_async) {
- vsyslog_async (prio, fmt, ap);
- } else
-#endif
- {
-#if HAVE_VSYSLOG
- vsyslog (prio, fmt, ap);
-#else
- char buf[128];
- vsnprintf (buf, sizeof buf, fmt, ap);
- syslog (prio, "%s", buf);
-#endif
- }
- return 0;
-}
-
-#ifdef USE_SYSLOG_ASYNC
-void
-mf_gacopyz_syslog_async_log_printer(int level, char *fmt, va_list ap)
-{
- switch (level) {
- case SMI_LOG_DEBUG:
- level = LOG_DEBUG;
- break;
- case SMI_LOG_INFO:
- level = LOG_INFO;
- break;
- case SMI_LOG_WARN:
- level = LOG_WARNING;
- break;
- case SMI_LOG_ERR:
- level = LOG_ERR;
- break;
-
- case SMI_LOG_FATAL:
- default:
- level = LOG_EMERG;
- }
- vsyslog_async(level, fmt, ap);
-}
-#endif
-
-int
-syslog_error_printer (const char *fmt, va_list ap)
-{
- return syslog_printer(LOG_ERR, fmt, ap);
-}
-
-int
-stderr_error_printer (const char *fmt, va_list ap)
-{
- fprintf(stderr, "%s: ", program_invocation_short_name);
- vfprintf(stderr, fmt, ap);
- fputc ('\n', stderr);
- return 0;
-}
-
-void
-vlogmsg(int prio, const char *fmt, va_list ap)
-{
- if (log_to_stderr) {
- vfprintf(stderr, fmt, ap);
- fprintf(stderr, "\n");
- } else
- syslog_printer(prio, fmt, ap);
-}
-
-void
-logmsg(int prio, const char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- vlogmsg(prio, fmt, ap);
- va_end(ap);
-}
-
-void
-trace(const char *fmt, ...)
-{
- if (do_trace) {
- va_list ap;
- va_start(ap, fmt);
- vlogmsg(LOG_INFO, fmt, ap);
- va_end(ap);
- }
-}
-
-void
-debug_log(char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- vlogmsg(LOG_DEBUG, fmt, ap);
- va_end(ap);
-}
-
-void
-log_status(sfsistat status, SMFICTX *ctx)
-{
- int lev;
- debug_module_level(NULL, &lev);
- if (lev >= 1 && status != SMFIS_CONTINUE) {
- const char *str = sfsistat_str(status);
- if (str)
- logmsg(LOG_INFO,
- "%s%s", mailfromd_msgid(ctx), str);
- else
- logmsg(LOG_INFO,
- "%sstatus %d",
- mailfromd_msgid(ctx), status);
- }
-}
-
-static void
-mf_error_on_locus(mu_debug_t err, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
-#if MAILUTILS_VERSION_NUMBER >= 1290
- if (err) {
- mu_debug_vprintf(err, 0, fmt, ap);
- mu_debug_printf(err, 0, "\n");
- } else
-#endif
- mu_verror(fmt, ap);
- va_end(ap);
-}
-
-
-/* Sendmail class file support */
-
-static mu_list_t domain_list;
-
-int
-compare_string(const void *item, const void *value)
-{
- return strcmp(item, value);
-}
-
-/* Read domains from sendmail-style domain file NAME and store them in
- DOMAIN_LIST */
-int
-read_domain_file(mu_debug_t err, char *name)
-{
- FILE *fp;
- char buf[256];
- char *p;
-
- fp = fopen(name, "r");
- if (!fp) {
- mf_error_on_locus(err, _("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, compare_string);
- }
-
- while (p = fgets(buf, sizeof buf, fp)) {
- char *q;
-
- while (*p && isspace(*p))
- p++;
- if (*p == '#')
- continue;
-
- for (q = p + strlen(p) - 1; q > p && 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) {
- debug2(10,"%s is in relayed domain %s",
- name, p);
- return 1;
- }
- p = strchr(p, '.');
- if (p)
- p++;
- }
- return 0;
-}
-
-/* Return true if CLIENT represents a host we relay. CLIENT is a dotted-quad
- IP address. */
-int
-host_in_relayed_domain_p(char *client)
-{
- int rc;
- char *hbuf;
-
- if (mu_list_is_empty(domain_list))
- return 0;
-
- if (resolve_ipstr(client, &hbuf))
- return 0;
- rc = relayed_domain_p(hbuf);
- free(hbuf);
- return rc;
-}
-
-
-/* ************************************************************************
- Configuration directives and options.
-
- This is rather complicated. Mailfromd can take its configurable values
- from the following locations (in that order):
-
- 1. From the mailutils configuration file suite, $sysconfdir/mailutils.rc
- and/or any files included herein;
- 2. From #pragma statements in the filter script file,
- $sysconfdir/mailfromd.rc;
- 3. From command line options;
-
- Versions prior to 4.2.90 supported only [2] and [3]. Generally speaking,
- [2] was needed because Mailutils versions prior to 1.2.90 lacked proper
- configuration file support. With the advent of it, [2] became obsolete
- and will probably be removed in some point in the future.
-
- For the time being, however, I need to support all flavors of options,
- because it is reasonable to assume that many of the installers still have
- MU 1.2 or prior, with which [1] is not available.
-
- Technically speaking, [1] is supported by mu_app_init, whenever compiled
- with newer Mailutils, [2] is supported by the "option handling" code below,
- and [3] is handled by argp machinery (called either from mu_app_init, for
- MU >=1.2.90, or from mu_argp_parse, for older Mailutils versions).
-
- There are some functions common to [1] and [2], these are defined in this
- section.
- ************************************************************************ */
-
-static int
-gid_comp(const void *item, const void *data)
-{
- return (gid_t) item != (gid_t) data;
-}
-
-static int
-mf_option_group(mu_debug_t err, char *arg)
-{
- struct group *group = getgrnam(arg);
- if (group) {
- if (!retain_groups) {
- int rc = mu_list_create(&retain_groups);
- if (rc) {
- mf_error_on_locus(err,
- _("Cannot create list: %s"),
- mu_strerror(rc));
- return 1;
- }
- mu_list_set_comparator(retain_groups, gid_comp);
- }
- mu_list_append(retain_groups, (void*)group->gr_gid);
- } else {
- mf_error_on_locus(err, _("Unknown group: %s"), arg);
- return 1;
- }
- return 0;
-}
-
-static int
-mf_option_mailfrom(mu_debug_t err, char *arg)
-{
- int rc;
- mu_address_t addr;
-
- rc = mu_address_create(&addr, arg);
- if (rc) {
- mf_error_on_locus(err, _("Cannot create address `%s': %s"),
- arg, mu_strerror(rc));
- return 1;
- }
- mu_address_destroy(&addr);
- defer_initialize_variable("mailfrom_address", arg);
- return 0;
-}
-
-static int
-mf_option_state_directory(mu_debug_t err, char *arg)
-{
- struct stat st;
- if (stat(arg, &st)) {
- mf_error_on_locus(err, _("Cannot stat file `%s': %s"),
- arg,
- mu_strerror(errno));
- return 1;
- }
- if (!S_ISDIR(st.st_mode)) {
- mf_error_on_locus(err, _("`%s' is not a directory"), arg);
- return 1;
- }
- if (arg[0] != '/') {
- mf_error_on_locus(err,
- _("State directory `%s' is not an absolute file name"),
- arg);
- return 1;
- }
- mailfromd_state_dir = xstrdup(arg);
- return 0;
-}
-
-static int
-mf_option_source_ip(mu_debug_t err, char *arg, unsigned long *pval)
-{
- unsigned long address = inet_addr(arg);
- if (address == INADDR_NONE) {
- struct hostent *phe = gethostbyname(arg);
- if (!phe) {
- mf_error_on_locus(err, _("Cannot resolve `%s'"),
- arg);
- return 1;
- }
- address = *(((unsigned long **) phe->h_addr_list)[0]);
- }
- *pval = address;
- return 0;
-}
-
-
-/* Option handling.
-
- There are two classes of options: those that can be set using #pragma
- directive in the configuration file, and those that can be used only in
- command line.
-
- The latter are handled as usual. The former are processed in two stages:
- first, upon processing command line, their command line settings are
- verified and stored in struct option_cache below. Then, configuration
- file is parsed. Any valid `#pragma option' directives found there overwrite
- values in option_cache. Finally, process_options() is called that scans the
- cache and actually sets any options found there. */
-
-static int option_string(char *opt, void **pval, char *newval);
-
-static int
-option_ehlo(char *opt, void **pval, char *newval)
-{
- if (get_locus()->file)
- parse_warning(
- "`#pragma option ehlo' is deprecated, consider using "
- "`set ehlo_domain \"%s\"' instead",
- (char*) newval);
- else
- parse_warning(
- "option --ehlo is deprecated, consider using "
- "`-v ehlo_domain=\"%s\"' instead",
- (char*) newval);
- return option_string(opt, pval, newval);
-}
-
-static void
-set_ehlo(void *value)
-{
- defer_initialize_variable("ehlo_domain", value);
-}
-
-static int
-option_mailfrom(char *opt, void **pval, char *newval)
-{
- int rc;
- mu_address_t addr;
-
- /* FIXME-MU: compensate for mailutils deficiency */
- if (newval[0] == 0)
- newval = DEFAULT_FROM_ADDRESS;
- if (get_locus()->file)
- parse_warning(
- "`#pragma option mailfrom' is deprecated, consider using "
- "`set mailfrom_address \"%s\"' instead",
- (char*) newval);
- else
- parse_warning(
- "option --mailfrom is deprecated, consider using "
- "`-v mailfrom_address=\"%s\"' instead",
- (char*) newval);
-
- rc = mu_address_create(&addr, newval);
- if (rc) {
- mu_error(_("Cannot create address `%s': %s"),
- newval, mu_strerror(rc));
- return 1;
- }
- mu_address_destroy(&addr);
- return option_string(opt, pval, newval);
-}
-
-static void
-set_mailfrom(void *value)
-{
- int rc;
- mu_address_t addr;
-
- /* FIXME-MU: compensate for mailutils deficiency */
- if (*(char*)value == 0)
- value = DEFAULT_FROM_ADDRESS;
-
- rc = mu_address_create(&addr, value);
- if (rc) {
- mu_error(_("Cannot create address `%s': %s"),
- (char*)value, mu_strerror(rc));
- return;
- }
- mu_address_destroy(&addr);
- defer_initialize_variable("mailfrom_address", value);
-}
-
-
-/* Other options */
-
-static void
-set_debug(void *value)
-{
- debug_parse_spec(value);
-}
-
-static void
-set_positive_expire(void *value)
-{
- cache_format->expire_interval = *(time_t*) value;
- free(value);
-}
-
-static void
-set_negative_expire(void *value)
-{
- negative_expire_interval = *(time_t*) value;
- free(value);
-}
-
-static void
-set_expire(void *value)
-{
- expire_interval = *(time_t*) value;
- free(value);
-}
-
-static void
-set_rates_expire(void *value)
-{
- rate_format->expire_interval = *(time_t*) value;
- free(value);
-}
-
-static void
-set_port(void *value)
-{
- portspec = value;
-}
-
-static void
-set_user(void *value)
-{
- user = value;
-}
-
-static void
-set_milter_timeout(void *value)
-{
- time_t to = *(time_t*) value;
- free(value);
- if (smfi_settimeout(to) == MI_FAILURE) {
- mu_error(_("Invalid milter timeout: %lu"), (unsigned long) to);
- exit(EX_USAGE);
- }
-}
-
-static void
-set_pidfile(void *value)
-{
- pidfile = value;
-}
-
-static void
-set_io_timeout(void *value)
-{
- io_timeout = *(time_t*) value;
- free(value);
-}
-
-static void
-set_connect_timeout(void *value)
-{
- connect_timeout = *(time_t*) value;
- free(value);
-}
-
-static void
-set_response_timeout(void *value)
-{
- response_timeout = *(time_t*) value;
- free(value);
-}
-
-static int
-load_relay_file(void *item, void *data)
-{
- read_domain_file(NULL, item);
- return 0;
-}
-
-static void
-set_relay(void *value)
-{
- mu_list_do(value, load_relay_file, NULL);
-}
-
-static void
-set_source(void *value)
-{
- source_address = *(unsigned long*)value;
-}
-
-static void
-set_group(void *value)
-{
- /* do nothing */
-}
-
-void
-set_source_info(void *value)
-{
- source_info_option = (int) value;
-}
-
-void
-set_stack_trace(void *value)
-{
- stack_trace_option = (int) value;
-}
-
-static void
-set_lock_retry_count(void *value)
-{
- lock_retry_count_option = strtoul(value, NULL, 0);
-}
-
-static void
-set_lock_retry_timeout(void *value)
-{
- lock_retry_timeout_option = *(time_t*) value;
- free(value);
-}
-
-static int
-option_string(char *opt, void **pval, char *newval)
-{
- if (*pval)
- free(*pval);
- *pval = strdup(newval);
- return 0;
-}
-
-static int
-option_number(char *opt, void **pval, char *newval)
-{
- char *p;
-
- strtoul(newval, &p, 10);
- if (*p) {
- errno = EINVAL;
- return 1;
- }
- return option_string(opt, pval, newval);
-}
-
-static int
-option_boolean(char *opt, void **pval, char *newval)
-{
- int val;
-
- if (strcmp (newval, "yes") == 0
- || strcmp (newval, "true") == 0
- || strcmp (newval, "t") == 0)
- val = 1;
- else if (strcmp (newval, "no") == 0
- || strcmp (newval, "false") == 0
- || strcmp (newval, "nil") == 0)
- val = 0;
- else {
- char *p;
-
- val = strtoul(newval, &p, 10);
- if (*p) {
- errno = EINVAL;
- return 1;
- }
- }
-
- *pval = (void*) val;
- return 0;
-}
-
-static int
-option_debug(char *opt, void **pval, char *newval)
-{
- return option_string(opt, pval, newval);
-}
-
-static int
-option_time(char *opt, void **pval, char *newval)
-{
- time_t interval;
- const char *endp;
- if (parse_time_interval(newval, &interval, &endp)) {
- mu_error(_("%s: unrecognized time format (near `%s')"),
- opt, endp);
- return 1;
- }
- if (!*pval)
- *pval = xmalloc(sizeof(time_t));
- *(time_t*) *pval = interval;
- return 0;
-}
-
-static int
-option_pidfile(char *opt, void **pval, char *newval)
-{
- if (newval[0] != '/') {
- mu_error(_("Invalid pidfile name: must be absolute"));
- return 1;
- }
- return option_string(opt, pval, newval);
-}
-
-static int
-option_relay(char *opt, void **pval, char *newval)
-{
- if (!*pval)
- mu_list_create((mu_list_t*)pval);
- mu_list_append(*pval, strdup(newval));
- return 0;
-}
-
-static int
-option_source(char *opt, void **pval, char *newval)
-{
- unsigned long address;
-
- if (mf_option_source_ip(NULL, newval, &address))
- return 1;
-
- if (*pval == 0)
- *pval = xmalloc (sizeof address);
- *(unsigned long*)*pval = address;
- return 0;
-}
-
-static int
-option_group(char *opt, void **pval, char *newval)
-{
- return mf_option_group(NULL, newval);
-}
-
-void
-set_state_directory(void *value)
-{
- /* nothing */
-}
-
-int
-option_state_directory(char *opt, void **pval, char *newval)
-{
- return mf_option_state_directory(NULL, newval);
-}
-
-struct option_cache {
- char *name;
- void *value;
- int (*handler)(char *opt, void **pval, char *newval);
- void (*set)(void *value);
- int cumulative;
-} option_cache[] = {
- { "ehlo", NULL, option_ehlo, set_ehlo },
- { "debug", NULL, option_debug, set_debug },
- { "source-info", NULL, option_boolean, set_source_info },
- { "stack-trace", NULL, option_boolean, set_stack_trace },
- { "expire-interval", NULL, option_time, set_expire },
- { "positive-expire-interval", NULL, option_time, set_positive_expire },
- { "negative-expire-interval", NULL, option_time, set_negative_expire },
- { "rates-expire-interval", NULL, option_time, set_rates_expire },
- { "port", NULL, option_string, set_port }, /* FIXME: option_port */
- { "user", NULL, option_string, set_user },
- { "group", NULL, option_group, set_group },
- { "milter-timeout", NULL, option_time, set_milter_timeout },
- { "pidfile", NULL, option_pidfile, set_pidfile },
- { "mailfrom", NULL, option_mailfrom, set_mailfrom },
- { "timeout", NULL, option_time, set_io_timeout },
- { "io-timeout", NULL, option_time, set_io_timeout },
- { "connect-timeout", NULL, option_time, set_connect_timeout },
- { "initial-response-timeout", NULL, option_time,
- set_response_timeout },
- { "relay", NULL, option_relay, set_relay, 1 },
- { "source", NULL, option_source, set_source },
- { "lock-retry-count", NULL, option_number, set_lock_retry_count },
- { "lock-retry-timeout", NULL, option_time, set_lock_retry_timeout },
- { "state-directory", NULL, option_state_directory, set_state_directory },
- { NULL }
-};
-
-static struct option_cache *
-find_option(char *name)
-{
- struct option_cache *p;
-
- for (p = option_cache; p->name; p++)
- if (strcmp(p->name, name) == 0)
- return p;
- return NULL;
-}
-
-int
-set_option(char *name, char *value, int override)
-{
- struct option_cache *p = find_option(name);
- if (!p) {
- errno = ENOENT;
- return 1;
- }
- if (!p->cumulative && !override && p->value)
- return 0;
- return p->handler(name, &p->value, value);
-}
-
-void
-process_options()
-{
- struct option_cache *p;
-
- for (p = option_cache; p->name; p++)
- if (p->value && p->set)
- p->set(p->value);
-}
-
-
-/* Command line parsing */
-
-const char *program_version = "mailfromd (" PACKAGE_STRING ")";
-static char doc[] = N_("mailfromd -- a general purpose milter daemon");
-static char args_doc[] = "[var=value...][SCRIPT]";
-
-enum mailfromd_option {
- OPTION_ALL = 256,
- OPTION_COMPACT,
- OPTION_CONFIG_FILE,
- OPTION_DAEMON,
- OPTION_DELETE,
- OPTION_DOMAIN_FILE,
- OPTION_DUMP_CODE,
- OPTION_DUMP_GRAMMAR_TRACE,
- OPTION_DUMP_LEX_TRACE,
- OPTION_DUMP_MACROS,
- OPTION_DUMP_TREE,
- OPTION_DUMP_XREF,
- OPTION_EXPIRE,
- OPTION_FOREGROUND,
- OPTION_GACOPYZ_LOG,
- OPTION_IGNORE_FAILED_READS,
- OPTION_LINT,
- OPTION_LOG_TAG,
- OPTION_LIST,
- OPTION_LOCK_RETRY_COUNT,
- OPTION_LOCK_RETRY_TIMEOUT,
- OPTION_MILTER_TIMEOUT,
- OPTION_MTASIM,
- OPTION_NO_PREPROCESSOR,
- OPTION_NO_SYSLOG_ASYNC,
- OPTION_PIDFILE,
- OPTION_POSTMASTER_EMAIL,
- OPTION_PREDICT_NEXT,
- OPTION_PREPROCESSOR,
- OPTION_SHOW_DEFAULTS,
- OPTION_SINGLE_PROCESS,
- OPTION_STACK_TRACE,
- OPTION_STATE_DIRECTORY,
- OPTION_SOURCE_INFO,
- OPTION_SYSLOG,
- OPTION_SYSLOG_ASYNC,
- OPTION_TIME_FORMAT,
- OPTION_TIMEOUT,
- OPTION_TRACE,
- OPTION_TRACE_PROGRAM,
-};
-
-static struct argp_option options[] = {
-#define GRP 0
- { NULL, 0, NULL, 0,
- N_("Operation modifiers"), GRP },
- { "delete", OPTION_DELETE, NULL, 0,
- N_("Delete given entries from the database"), GRP+1 },
- { "list", OPTION_LIST, NULL, 0,
- N_("List given database (default cache)"), GRP+1 },
- { "expire", OPTION_EXPIRE, NULL, 0,
- N_("Delete expired entries from the database"), GRP+1 },
- { "compact", OPTION_COMPACT, NULL, 0,
- N_("Compact the database"), GRP+1 },
- { "test", 't', N_("HANDLER"), OPTION_ARG_OPTIONAL,
- N_("Run in test mode"), GRP+1 },
- { "lint", OPTION_LINT, NULL, 0,
- N_("Check syntax and exit"), GRP+1 },
- { "syntax-check", 0, NULL, OPTION_ALIAS, NULL, GRP+1 },
- { "show-defaults", OPTION_SHOW_DEFAULTS, NULL, 0,
- N_("Show compilation defaults"), GRP+1 },
- { "daemon", OPTION_DAEMON, NULL, 0,
- N_("Run in daemon mode (default)"), GRP+1 },
-
- { NULL, 'E', NULL, 0,
- N_("Preprocess source files and exit"), GRP+1 },
- /* Reserved for future use: */
- { "compile", 'c', NULL, OPTION_HIDDEN,
- N_("Compile files"), GRP+1 },
- { "load", 'l', N_("FILE"), OPTION_HIDDEN,
- N_("Load library"), GRP+1 },
- { "load-dir", 'L', N_("DIR"), OPTION_HIDDEN,
- N_("Add DIR to the load path"), GRP+1 },
-
-#undef GRP
-#define GRP 15
- { NULL, 0, NULL, 0,
- N_("Database management options"), GRP },
- { "file", 'f', N_("FILE"), 0,
- N_("DB file name to operate upon"),
- GRP+1 },
- { "format", 'H', N_("FORMAT"), 0,
- N_("Format of the DB file to operate upon"), GRP+1 },
- { "ignore-failed-reads", OPTION_IGNORE_FAILED_READS, NULL, 0,
- N_("Ignore failed reads while compacting the database"), GRP+1 },
- { "predict", OPTION_PREDICT_NEXT, N_("RATE"), 0,
- N_("Predict when the user will be able to send next message"),
- GRP+1 },
- { "lock-retry-count", OPTION_LOCK_RETRY_COUNT, N_("NUMBER"), 0,
- N_("Set maximum number of attempts to acquire the lock"), GRP+1 },
- { "lock-retry-timeout", OPTION_LOCK_RETRY_TIMEOUT, N_("TIME"), 0,
- N_("Set timeout for acquiring the lockfile"), GRP+1 },
- { "expire-interval", 'e', N_("NUMBER"), 0,
- N_("Set database expiration interval to NUMBER seconds"), GRP+1 },
- { "all", OPTION_ALL, NULL, 0,
- N_("With --compact or --expire: apply the operation to all "
- "available databases"), GRP+1 },
- { "time-format", OPTION_TIME_FORMAT, N_("FMT"), 0,
- N_("Output timestamps using given format (default \"%c\")"), GRP+1 },
-
-#undef GRP
-#define GRP 20
- { NULL, 0, NULL, 0,
- N_("General options"), GRP },
- { "state-directory", OPTION_STATE_DIRECTORY, N_("DIR"), 0,
- N_("Set new program state directory"), GRP+1 },
- { "config-file", OPTION_CONFIG_FILE, N_("FILE"), OPTION_HIDDEN,
- N_("Read configuration from FILE"), GRP+1 },
- { "include", 'I', N_("DIR"), 0,
- N_("Add the directory DIR to the list of directories to be "
- "searched for header files"), GRP+1 },
- { "port", 'p', N_("STRING"), 0,
- N_("Set communication socket"), GRP+1 },
- { "remove", 'r', NULL, 0,
- N_("Force removing local socket file, if it already exists"),
- GRP+1 },
- { "foreground", OPTION_FOREGROUND, NULL, 0,
- N_("Stay in foreground"), GRP+1 },
- { "mtasim", OPTION_MTASIM, NULL, 0,
- N_("Run in mtasim compatibility mode"), GRP+1 },
- { "single-process", OPTION_SINGLE_PROCESS, NULL, 0,
- N_("Run in single-process mode"), GRP+1 },
- { "pidfile", OPTION_PIDFILE, N_("FILE"), 0,
- N_("Set pidfile name"), GRP+1 },
- { "user", 'u', N_("NAME"), 0,
- N_("Switch to this user privileges after startup"), GRP+1 },
- { "group", 'g', N_("NAME"), 0,
- N_("Retain the supplementary group NAME when switching to user "
- "privileges"),
- GRP+1 },
- { "source", 'S', N_("ADDRESS"), 0,
- N_("Set source address for TCP connections"), GRP+1 },
- { "optimize", 'O', N_("LEVEL"), OPTION_ARG_OPTIONAL,
- N_("Set code optimization level"), GRP+1 },
- { "variable", 'v', N_("VAR=VALUE"), 0,
- N_("Assign VALUE to VAR"), GRP+1 },
- { "relayed-domain-file", OPTION_DOMAIN_FILE, N_("FILE"), 0,
- N_("Read relayed domains from FILE"), GRP+1 },
- { "preprocessor", OPTION_PREPROCESSOR, N_("COMMAND"), 0,
- N_("Use command as external preprocessor"), GRP+1 },
- { "no-preprocessor", OPTION_NO_PREPROCESSOR, NULL, 0,
- N_("Disable the use of external preprocessor"), GRP+1 },
-#undef GRP
-
-#undef GRP
-#define GRP 30
- { NULL, 0, NULL, 0,
- N_("Timeout control"), GRP },
- { "milter-timeout", OPTION_MILTER_TIMEOUT, N_("TIME"), 0,
- N_("Set MTA connection timeout"), GRP+1 },
- { "timeout", OPTION_TIMEOUT, N_("TIME"), 0,
- N_("Set I/O operation timeout"), GRP+1 },
-
-#undef GRP
-#define GRP 40
- { NULL, 0, NULL, 0,
- N_("Informational and debugging options"), GRP },
- { "transcript", 'X', NULL, 0,
- N_("Enable transcript of SMTP sessions"), GRP+1 },
- { "trace", OPTION_TRACE, NULL, 0,
- N_("Trace executed actions"), GRP+1 },
- { "trace-program", OPTION_TRACE_PROGRAM, N_("MODULES"),
- OPTION_ARG_OPTIONAL,
- N_("Enable filter program tracing"), GRP+1 },
- { "debug", 'd', N_("LEVEL"), 0,
- N_("Set debugging level"), GRP+1 },
- { "dump-code", OPTION_DUMP_CODE, NULL, 0,
- N_("Dump disassembled code"), GRP+1 },
- { "dump-grammar-trace", OPTION_DUMP_GRAMMAR_TRACE, NULL, 0,
- N_("Dump grammar traces"), GRP+1 },
- { "dump-lex-trace", OPTION_DUMP_LEX_TRACE, NULL, 0,
- N_("Dump lexical analyzer traces"), GRP+1 },
- { "dump-tree", OPTION_DUMP_TREE, NULL, 0,
- N_("Dump parser tree"), GRP+1 },
- { "dump-macros", OPTION_DUMP_MACROS, NULL, 0,
- N_("Show used Sendmail macros"), GRP+1 },
- { "xref", OPTION_DUMP_XREF, NULL, 0,
- N_("Produce a cross-reference listing"), GRP+1 },
- { "dump-xref", 0, NULL, OPTION_ALIAS, NULL, GRP+1 },
- { "gacopyz-log", OPTION_GACOPYZ_LOG, N_("LEVEL"), 0,
- N_("Set Gacopyz log level"), GRP+1 },
- { "stderr", 's', NULL, 0,
- N_("Log to stderr"), GRP+1 },
- { "syslog", OPTION_SYSLOG, NULL, 0,
- N_("Log to syslog (default)"), GRP+1 },
-#ifdef USE_SYSLOG_ASYNC
- { "syslog-async", OPTION_SYSLOG_ASYNC, NULL, 0,
- N_("Use asynchronous syslog"), GRP+1 },
- { "no-syslog-async", OPTION_NO_SYSLOG_ASYNC, NULL, 0,
- N_("Use system syslog"), GRP+1 },
-#endif
- { "log-tag", OPTION_LOG_TAG, N_("STRING"), 0,
- N_("Set the identifier used in syslog messages to STRING"), GRP+1 },
- { "source-info", OPTION_SOURCE_INFO, NULL, 0,
- N_("Debug messages include source information"), GRP+1 },
- { "stack-trace", OPTION_STACK_TRACE, NULL, 0,
- N_("Enable stack traces on runtime errors"), GRP+1 },
-#undef GRP
-
- /*DEPRECATED OPTIONS*/
- { "domain", 'D', N_("STRING"), OPTION_HIDDEN, "", 1 },
- { "ehlo", 0, NULL, OPTION_ALIAS|OPTION_HIDDEN, NULL, 1 },
- { "postmaster-email", OPTION_POSTMASTER_EMAIL, N_("EMAIL"),
- OPTION_HIDDEN, "", 1 },
- { "mailfrom", 0, NULL, OPTION_ALIAS|OPTION_HIDDEN, NULL, 1 },
-
-#if 0
-/* This entry is to pacify `make check-docs'. The options below
- are defined in libmailutils.
- */
- { "log-facility", }
- { "mailer", }
-#endif
- { NULL }
-};
-
-static int
-validate_options()
-{
- if (all_option &&
- !(mode == MAILFROMD_COMPACT || mode == MAILFROMD_EXPIRE)) {
- mu_error(_("--all is meaningful only with --expire or --compact option"));
- return 1;
- }
- if (all_option && format_option)
- mu_error(_("--format is incompatible with --all"));
- return 0;
-}
-
-
-static error_t
-parse_opt (int key, char *arg, struct argp_state *state)
-{
- switch (key) {
- case 'D':
- set_option("ehlo", arg, 1);
- break;
-
- case 'd':
- set_option("debug", arg, 1);
- break;
-
- case 'E':
- preprocess_option = 1;
- break;
-
- case 'e':
- set_option("expire-interval", arg, 1);
- break;
-
- case 'f':
- file_option = arg;
- break;
-
- case 'H':
- format_option = db_format_lookup(arg);
- if (format_option == NULL)
- argp_error(state, _("Unknown database format: %s"),
- arg);
- break;
-
- case 'I':
- add_include_dir(arg);
- break;
-
- case OPTION_ALL:
- all_option = 1;
- break;
-
- case OPTION_CONFIG_FILE:
- /*DEPRECATION*/
- mu_error("Warning: --config-file is obsolete; give the filter script name as an argument");
- script_file = arg;
- break;
-
- case OPTION_IGNORE_FAILED_READS:
- ignore_failed_reads_option = 1;
- break;
-
- case OPTION_LOCK_RETRY_COUNT:
- set_option("lock-retry-count", arg, 1);
- break;
-
- case OPTION_LOCK_RETRY_TIMEOUT:
- set_option("lock-retry-timeout", arg, 1);
- break;
-
- case OPTION_PREDICT_NEXT:
- format_option = db_format_lookup("rate");
- if (convert_rate(arg, &predict_rate) == 0)
- predict_next_option = 1;
- mode = MAILFROMD_LIST;
- break;
-
- case OPTION_PREPROCESSOR:
- ext_pp = arg;
- break;
-
- case OPTION_NO_PREPROCESSOR:
- ext_pp = NULL;
- break;
-
- case OPTION_TIME_FORMAT:
- time_format_string = arg;
- break;
-
- case 'c':
- case 'l':
- case 'L':
- argp_error(state,
- _("The option `-%c' is not yet implemented"),
- key);
- break;
-
- case OPTION_LOG_TAG:
- syslog_tag = arg;
- break;
-
- case OPTION_LINT:
- log_to_stderr = 1;
- script_check = 1;
- need_config = 1;
- break;
-
- case 'p':
- set_option("port", arg, 1);
- break;
-
- case 'r':
- force_remove = 1;
- break;
-
- case 'O':
- if (!arg)
- optimization_level = 1;
- else {
- char *p;
- optimization_level = strtoul(arg, &p, 0);
- if (*p)
- argp_error(state,
- _("-O level must be a non-negative integer"));
- }
- break;
-
- case 'S':
- set_option("source", arg, 1);
- break;
-
- case 's':
- log_to_stderr = 1;
- break;
-
- case 't':
- mode = MAILFROMD_TEST;
- if (arg) {
- test_state = string_to_state(arg);
- if (test_state == smtp_state_none)
- argp_error(state,
- _("Unknown smtp state tag: %s"),
- arg);
- }
- log_to_stderr = 1;
- need_config = 1;
- break;
-
- case 'u':
- set_option("user", arg, 1);
- break;
-
- case 'g':
- set_option("group", arg, 1);
- break;
-
- case 'v':
- {
- char *p;
-
- p = strchr(arg, '=');
- if (!p)
- argp_error(state,
- _("Expected assignment, but found `%s'"),
- arg);
- *p++ = 0;
- defer_initialize_variable(arg, p);
- break;
- }
-
- case 'X':
- do_transcript = 1;
- break;
-
- case OPTION_COMPACT:
- need_config = 0;
- log_to_stderr = 1;
- mode = MAILFROMD_COMPACT;
- break;
-
- case OPTION_DAEMON:
- mode = MAILFROMD_DAEMON;
- need_config = 1;
- break;
-
- case OPTION_DELETE:
- need_config = 0;
- log_to_stderr = 1;
- mode = MAILFROMD_DELETE;
- break;
-
- case OPTION_DOMAIN_FILE:
- set_option("relay", arg, 1);
- break;
-
- case OPTION_DUMP_CODE:
- script_dump_code = 1;
- log_to_stderr = 1;
- break;
-
- case OPTION_DUMP_GRAMMAR_TRACE:
- script_ydebug = 1;
- log_to_stderr = 1;
- break;
-
- case OPTION_DUMP_LEX_TRACE:
- yy_flex_debug = 1;
- log_to_stderr = 1;
- break;
-
- case OPTION_DUMP_MACROS:
- script_dump_macros = 1;
- log_to_stderr = 1;
- break;
-
- case OPTION_DUMP_TREE:
- script_dump_tree = 1;
- log_to_stderr = 1;
- break;
-
- case OPTION_DUMP_XREF:
- script_dump_xref = 1;
- log_to_stderr = 1;
- break;
-
- case OPTION_EXPIRE:
- need_config = 0;
- log_to_stderr = 1;
- mode = MAILFROMD_EXPIRE;
- break;
-
- case OPTION_FOREGROUND:
- foreground = 1;
- break;
-
- case OPTION_GACOPYZ_LOG:
- {
- int lev = gacopyz_string_to_log_level(arg);
- if (lev == -1)
- argp_error(state,
- _("%s: invalid log level"),
- arg);
- smfi_setlogmask(SMI_LOG_FROM(lev));
- break;
- }
-
- case OPTION_LIST:
- need_config = 0;
- log_to_stderr = 1;
- mode = MAILFROMD_LIST;
- break;
-
- case OPTION_MILTER_TIMEOUT:
- set_option("milter-timeout", arg, 1);
- break;
-
- case OPTION_MTASIM:
- mtasim_option = foreground = 1;
- break;
-
- case OPTION_PIDFILE:
- set_option("pidfile", arg, 1);
- break;
-
- case OPTION_POSTMASTER_EMAIL:
- set_option("mailfrom", arg, 1);
- break;
-
- case OPTION_SHOW_DEFAULTS:
- mode = MAILFROMD_SHOW_DEFAULTS;
- need_config = 0;
- break;
-
- case OPTION_SINGLE_PROCESS:
- single_process_option = 1;
- break;
-
- case OPTION_STACK_TRACE:
- set_option("stack-trace", "yes", 1);
- break;
-
- case OPTION_STATE_DIRECTORY:
- set_option("state-directory", arg, 1);
- break;
-
- case OPTION_SOURCE_INFO:
- set_option("source-info", "yes", 1);
- break;
-
- case OPTION_SYSLOG:
- log_to_stderr = 0;
- break;
-
-#ifdef USE_SYSLOG_ASYNC
- case OPTION_SYSLOG_ASYNC:
- use_syslog_async = 1;
- break;
-
- case OPTION_NO_SYSLOG_ASYNC:
- use_syslog_async = 0;
- break;
-#endif
- case OPTION_TIMEOUT:
- set_option("timeout", arg, 1);
- break;
-
- case OPTION_TRACE:
- do_trace = 1;
- break;
-
- case OPTION_TRACE_PROGRAM:
- enable_prog_trace(arg ? arg: "all");
- break;
-
- case ARGP_KEY_INIT:
- smfi_setlogmask(SMI_LOG_FROM(SMI_LOG_WARN));
- break;
-
- case ARGP_KEY_FINI:
- if (validate_options())
- exit(EX_USAGE);
-
- if (!syslog_tag)
- syslog_tag = program_invocation_short_name;
-
- if (!format_option)
- format_option = db_format_lookup("cache");
- break;
-
- default:
- return ARGP_ERR_UNKNOWN;
- }
- return 0;
-}
-
-static const char *capa[] = {
- "auth",
- "common",
- "logging",
- "mailer",
- NULL
-};
-
-static struct argp argp = {
- options,
- parse_opt,
- args_doc,
- doc,
- NULL,
- NULL,
- NULL
-};
-
-
-/* Mailutils-2.0 configuration */
-#if MAILUTILS_VERSION_NUMBER >= 1290
-int
-cb_timeout(time_t *pinterval, mu_debug_t err, void *data, char *arg)
-{
- const char *endp;
- if (parse_time_interval(arg, pinterval, &endp)) {
- mf_error_on_locus(err,
- _("unrecognized time format (near `%s')"),
- endp);
- return 1;
- }
- return 0;
-}
-
-int
-cb_milter_timeout(mu_debug_t err, void *data, char *arg)
-{
- time_t interval;
-
- if (cb_timeout(&interval, err, data, arg))
- return 1;
- if (smfi_settimeout(interval) == MI_FAILURE) {
- mf_error_on_locus(err,
- _("%s:%d: Invalid milter timeout: %lu"),
- (unsigned long) interval);
- exit(EX_USAGE);
- }
-
- return 0;
-}
-
-int
-cb_io_timeout(mu_debug_t err, void *data, char *arg)
-{
- if (cb_timeout(&io_timeout, err, data, arg))
- return 1;
- return 0;
-}
-
-int
-cb_connect_timeout(mu_debug_t err, void *data, char *arg)
-{
- if (cb_timeout(&connect_timeout, err, data, arg))
- return 1;
- return 0;
-}
-
-int
-cb_initial_response_timeout(mu_debug_t err, void *data, char *arg)
-{
- if (cb_timeout(&response_timeout, err, data, arg))
- return 1;
- return 0;
-}
-
-int
-cb_lock_retry_timeout(mu_debug_t err, void *data, char *arg)
-{
- if (cb_timeout(&lock_retry_timeout_option, err, data, arg))
- return 1;
- return 0;
-}
-
-int
-cb_set_variable(mu_debug_t err, void *data, char *arg)
-{
- char *p, *value;
- char *tmp = NULL;
-
- for (p = arg; !(*p == ' ' || *p == '\t'); p++)
- if (!*p) {
- mf_error_on_locus(err, _("missing value"));
- return 1;
- }
- *p++ = 0;
-
- for (; *p == ' ' || *p == '\t'; p++)
- if (!*p) {
- mf_error_on_locus(err, _("missing value"));
- return 1;
- }
-
- if (*p == '"' || *p == '\'') {
- size_t len = strlen(p) + 1;
- tmp = xmalloc(len);
- mu_argcv_unquote_copy(tmp, p, len);
- value = tmp;
- } else
- value = p;
-
- defer_initialize_variable(arg, value);
- free(tmp);
- return 0;
-}
-
-int
-cb_ehlo_domain(mu_debug_t err, void *data, char *arg)
-{
- defer_initialize_variable("ehlo_domain", arg);
- return 0;
-}
-
-int
-cb_mail_from_address(mu_debug_t err, void *data, char *arg)
-{
- return mf_option_mailfrom(err, arg);
-}
-
-int
-cb_debug(mu_debug_t err, void *data, char *arg)
-{
- debug_parse_spec(arg);
- return 0;
-}
-
-/* See also option_group. */
-int
-cb_group(mu_debug_t err, void *data, char *arg)
-{
- return mf_option_group(err, arg);
-}
-
-int
-cb_state_directory(mu_debug_t err, void *data, char *arg)
-{
- return mf_option_state_directory(err, arg);
-}
-
-int
-cb_relay_file(mu_debug_t err, void *data, char *arg)
-{
- return read_domain_file(err, arg);
-}
-
-int
-cb_source_ip(mu_debug_t err, void *data, char *arg)
-{
- return mf_option_source_ip(err, arg, &source_address);
-}
-
-int
-cb_include_path(mu_debug_t err, void *data, char *arg)
-{
- char *p, *sp;
-
- for (p = strtok_r(arg, ":", &sp); p; p = strtok_r(NULL, ":", &sp))
- add_include_dir(p);
- return 0;
-}
-
-/* Keep alphabetical ordering of statements */
-struct mu_cfg_param mf_cfg_param[] = {
- { "debug", mu_cfg_callback, NULL, 0, cb_debug,
- N_("Set Mailfromd debug verbosity level. Argument is a comma-"
- "separated list of debug specifications, each of which has the "
- "following form:\n"
- " <module: string>[=<level: number>]\n"
- "where <module> is the name of a Mailfromd module, and <level> "
- "is the desired verbosity level for that module."),
- N_("spec: list") },
- { "source-info", mu_cfg_bool, &source_info_option, 0, NULL,
- N_("Debug messages include mailfromd source locations.") },
- { "stack-trace", mu_cfg_bool, &stack_trace_option, 0, NULL,
- N_("Dump stack traces on runtime errors.") },
- { "connect-timeout", mu_cfg_callback, NULL, 0, cb_connect_timeout,
- N_("Set SMTP connect timeout."),
- N_("time") },
- { "initial-response-timeout", mu_cfg_callback, NULL, 0,
- cb_initial_response_timeout,
- N_("Timeout for initial SMTP response."),
- N_("time") },
- { "io-timeout", mu_cfg_callback, NULL, 0, cb_io_timeout,
- N_("Timeout for SMTP I/O operations."),
- N_("time") },
- { "milter-timeout", mu_cfg_callback, NULL, 0, cb_milter_timeout,
- N_("Set milter timeout."),
- N_("time") },
- { "ehlo-domain", mu_cfg_callback, NULL, 0, cb_ehlo_domain,
- N_("Set the domain name for EHLO command.") },
- { "mail-from-address", mu_cfg_callback, NULL, 0, cb_mail_from_address,
- N_("Set email address for use in SMTP `MAIL FROM' command. "
- "Argument is an email address or a comma-separated list of "
- "addresses. Use <> for null address. Other addresses can "
- "be given without angle brackets."),
- N_("addr") },
- { "group", mu_cfg_callback, NULL, 0, cb_group,
- N_("Retain the supplementary group <name> when switching to user "
- "privileges") },
- { "user", mu_cfg_string, &user, 0, NULL,
- N_("Switch to this user privileges after startup.") },
- { "include-path", mu_cfg_callback, NULL, 0, cb_include_path,
- N_("Add directories to the list of directories to be searched for "
- "header files. Argument is a comma-separated list of "
- "directory names."),
- N_("path") },
- { "lock-retry-count", mu_cfg_size, &lock_retry_count_option, 0, NULL,
- N_("Retry acquiring DBM file lock this number of times.") },
- { "lock-retry-timeout", mu_cfg_callback, NULL, 0,
- cb_lock_retry_timeout,
- N_("Set the time span between the two DBM locking attempts."),
- N_("time") },
- { "pidfile", mu_cfg_string, &pidfile, 0, NULL,
- N_("Set file to store PID value in."),
- N_("file") },
- { "relay-file", mu_cfg_callback, NULL, 0, cb_relay_file,
- N_("Read relayed domains from <file>."),
- N_("file") },
- { "setvar", mu_cfg_callback, NULL, 0, cb_set_variable,
- N_("Initialize a mailfromd variable. Argument must be:\n"
- " <var: string> <value: string-or-number>\n"
- "where <var> is mailfromd variable name and <value> is a value "
- "to be assigned to it.") },
- { "script-file", mu_cfg_string, &script_file, 0, NULL,
- N_("Read filter stript from <file>."),
- N_("file") },
- /* FIXME: Could have used mu_cfg_ipv4 here, but... */
- { "source-ip", mu_cfg_callback, NULL, 0, cb_source_ip,
- N_("Set source address for TCP connections."),
- N_("ip: ipaddr") },
- { "state-directory", mu_cfg_callback, NULL, 0, cb_state_directory,
- N_("Set program state directory."),
- N_("dir") },
- { NULL }
-};
-#endif
-
-
-/* Auxiliary functions */
-
-/* Switch to the given UID/GID */
-int
-switch_to_privs(uid_t uid, gid_t gid)
-{
- int rc = 0;
- gid_t *emptygidset;
- size_t size = 1, j = 1;
- mu_iterator_t itr;
-
- if (uid == 0) {
- mu_error(_("Refusing to run as root"));
- return 1;
- }
-
- /* Create a list of supplementary groups */
- mu_list_count (retain_groups, &size);
- size++;
- emptygidset = xmalloc (size * sizeof emptygidset[0]);
- emptygidset[0] = gid ? gid : getegid();
-
- if (mu_list_get_iterator(retain_groups, &itr) == 0) {
- for (mu_iterator_first (itr);
- !mu_iterator_is_done (itr); mu_iterator_next (itr))
- mu_iterator_current (itr,
- (void **)(emptygidset + j++));
- mu_iterator_destroy(&itr);
- }
-
- /* Reset group permissions */
- if (geteuid() == 0 && setgroups(j, emptygidset)) {
- mu_error(_("setgroups(1, %lu) failed: %s"),
- (unsigned long) emptygidset[0],
- mu_strerror(errno));
- rc = 1;
- }
- free(emptygidset);
-
- /* Switch to the user's gid. On some OSes the effective gid must
- be reset first */
-
-#if defined(HAVE_SETEGID)
- if ((rc = setegid(gid)) < 0)
- mu_error(_("setegid(%lu) failed: %s"),
- (unsigned long) gid, mu_strerror(errno));
-#elif defined(HAVE_SETREGID)
- if ((rc = setregid(gid, gid)) < 0)
- mu_error(_("setregid(%lu,%lu) failed: %s"),
- (unsigned long) gid, (unsigned long) gid,
- mu_strerror(errno));
-#elif defined(HAVE_SETRESGID)
- if ((rc = setresgid(gid, gid, gid)) < 0)
- mu_error(_("setresgid(%lu,%lu,%lu) failed: %s"),
- (unsigned long) gid,
- (unsigned long) gid,
- (unsigned long) gid,
- mu_strerror(errno));
-#endif
-
- if (rc == 0 && gid != 0) {
- if ((rc = setgid(gid)) < 0 && getegid() != gid)
- mu_error(_("setgid(%lu) failed: %s"),
- (unsigned long) gid, mu_strerror(errno));
- if (rc == 0 && getegid() != gid) {
- mu_error(_("Cannot set effective gid to %lu"),
- (unsigned long) gid);
- rc = 1;
- }
- }
-
- /* Now reset uid */
- if (rc == 0 && uid != 0) {
- uid_t euid;
-
- if (setuid(uid)
- || geteuid() != uid
- || (getuid() != uid
- && (geteuid() == 0 || getuid() == 0))) {
-
-#if defined(HAVE_SETREUID)
- if (geteuid() != uid) {
- if (setreuid(uid, -1) < 0) {
- mu_error(_("setreuid(%lu,-1) failed: %s"),
- (unsigned long) uid,
- mu_strerror(errno));
- rc = 1;
- }
- if (setuid(uid) < 0) {
- mu_error(_("second setuid(%lu) failed: %s"),
- (unsigned long) uid,
- mu_strerror(errno));
- rc = 1;
- }
- } else
-#endif
- {
- mu_error(_("setuid(%lu) failed: %s"),
- (unsigned long) uid,
- mu_strerror(errno));
- rc = 1;
- }
- }
-
- euid = geteuid();
- if (uid != 0 && setuid(0) == 0) {
- mu_error(_("seteuid(0) succeeded when it should not"));
- rc = 1;
- } else if (uid != euid && setuid(euid) == 0) {
- mu_error(_("Cannot drop non-root setuid privileges"));
- rc = 1;
- }
-
- }
-
- return rc;
-}
-
-void
-priv_setup()
-{
- if (getuid() == 0) {
- if (!user) {
- mu_error(_("When running as root, --user option is mandatory."));
- exit(EX_USAGE);
- } else {
- struct passwd *pw = getpwnam(user);
- if (!pw) {
- mu_error(_("No such user: %s"), user);
- exit(EX_SOFTWARE);
- }
- if (pw && switch_to_privs(pw->pw_uid, pw->pw_gid))
- exit(EX_SOFTWARE);
- }
- }
-}
-
-void
-assert_db_format()
-{
- if (!format_option) {
- mu_error(_("Operation is not applicable"));
- exit(EX_USAGE);
- }
-}
-
-char *
-get_db_name()
-{
- assert_db_format();
- if (file_option)
- return file_option;
- if (format_option->dbname)
- return format_option->dbname;
- mu_error(_("Database file name is not given"));
- exit(EX_USAGE);
-}
-
-void
-init_names()
-{
- mailfromd_state_dir = xstrdup(DEFAULT_STATE_DIR);
- portspec = xstrdup(DEFAULT_SOCKET);
- pidfile = xstrdup(DEFAULT_PIDFILE);
-}
-
-void
-db_format_setup()
-{
- dns_cache_format = db_format_install(dns_cache_format);
- cache_format = db_format_install(cache_format);
- rate_format = db_format_install(rate_format);
- greylist_format = db_format_install(greylist_format);
-}
-
-static char *
-state_dir_fixup(char *name)
-{
- if (name[0] != '/') {
- size_t slen = strlen(mailfromd_state_dir);
- size_t olen = strlen(name);
- size_t flen = slen + 1 + olen + 1;
- char *p = xrealloc(name, flen);
- memmove(p + slen + 1, p, olen + 1);
- memcpy(p, mailfromd_state_dir, slen);
- p[slen] = '/';
- name = p;
- }
- return name;
-}
-
-static int
-db_fixup_name_enumerator(void *sym, void *data)
-{
- struct db_format *fmt = sym;
-
- fmt->dbname = state_dir_fixup(fmt->dbname);
-
- return 0;
-}
-
-static void
-portspec_fixup()
-{
- char *proto, *port, *path;
-
- if (gacopyz_parse_connection(portspec, &proto, &port, &path)
- != MI_SUCCESS)
- return; /* No need to complain: it is left to gacopyz connect
- routines */
-
- if ((!proto
- || strcmp(proto, "unix") == 0 || strcmp(proto, "local") == 0)
- && !port
- && path[0] != '/') {
- portspec = state_dir_fixup(path);
- path = NULL;
- }
-
- free(proto);
- free(port);
- free(path);
-}
-
-static void
-fixup_state_dir_names()
-{
- size_t slen = strlen(mailfromd_state_dir);
- if (mailfromd_state_dir[slen-1] == '/')
- mailfromd_state_dir[slen-1] = 0;
- db_format_enumerate(db_fixup_name_enumerator, NULL);
- pidfile = state_dir_fixup(pidfile);
- portspec_fixup();
-}
-
-void
-mailfromd_delete(int argc, char **argv)
-{
- int i;
- char *name = get_db_name();
-
- for (i = 0; i < argc; i++) {
- debug2(50,"deleting %s info for %s",
- format_option->name, argv[i]);
- db_delete(name, argv[i]);
- }
-}
-
-void
-mailfromd_list(int argc, char **argv)
-{
- int rc;
- char *name = get_db_name();
-
- if (!format_option->print_item) {
- /* Should not happen */
- mu_error(_("List is not applicable to this DB format"));
- exit(EX_USAGE);
- }
-
- rc = 0;
- if (argc) {
- int i;
- for (i = 0; i < argc; i++)
- rc += db_list_item(name, argv[i],
- format_option->print_item);
- } else
- rc = db_list(name, format_option->print_item);
- exit(rc != 0);
-}
-
-static int
-db_proc_enumerator(void *sym, void *data)
-{
- struct db_format *fmt = sym;
- int (*func)(char *name, db_expire_t exp) = data;
-
- if (fmt->expire)
- func(fmt->dbname, fmt->expire);
- return 0;
-}
-
-void
-mailfromd_expire()
-{
- priv_setup();
- if (all_option)
- db_format_enumerate(db_proc_enumerator, db_expire);
- else {
- if (!format_option->expire) {
- mu_error(_("Expire is not applicable to this DB format"));
- exit(EX_USAGE);
- }
- exit(db_expire(get_db_name(), format_option->expire) != 0);
- }
-}
-
-void
-mailfromd_compact()
-{
- priv_setup();
- if (all_option)
- db_format_enumerate(db_proc_enumerator, db_compact);
- else {
- if (!format_option->expire) {
- mu_error(_("Compact is not applicable to this DB format"));
- exit(EX_USAGE);
- }
- exit(db_compact(get_db_name(), format_option->expire) != 0);
- }
-}
-
-static int
-db_format_enumerator(void *sym, void *data)
-{
- struct db_format *fmt = sym;
-
- printf("%s database: %s\n", fmt->name, fmt->dbname);
- if (strcmp(fmt->name, "cache") == 0) {
- printf("%s positive expiration: %lu\n", fmt->name,
- fmt->expire_interval);
- printf("%s negative expiration: %lu\n", fmt->name,
- negative_expire_interval);
- } else if (strcmp(fmt->name, "dns") == 0) {
- printf("%s negative expiration: %lu\n", fmt->name,
- fmt->expire_interval);
- } else
- printf("%s expiration: %lu\n", fmt->name,
- fmt->expire_interval);
- return 0;
-}
-
-void
-mailfromd_show_defaults()
-{
- printf("version: %s\n", VERSION);
- printf("script file: %s\n", script_file);
- printf("preprocessor: %s\n", ext_pp ? ext_pp : "none");
- printf("user: %s\n", user);
- printf("statedir: %s\n", mailfromd_state_dir);
- printf("socket: %s\n", portspec);
- printf("pidfile: %s\n", pidfile);
-#ifdef USE_SYSLOG_ASYNC
-#if DEFAULT_SYSLOG_ASYNC == 1
- printf("default syslog: non-blocking\n");
-#else
- printf("default syslog: blocking\n");
-#endif
-#endif
- printf("database format: ");
-#if defined WITH_GDBM
- printf("GDBM");
-#elif defined WITH_BDB
- printf("Berkeley DB %d.x", WITH_BDB);
-#endif
- printf("\n");
-
- db_format_enumerate(db_format_enumerator, NULL);
-}
-
-void
-log_setup(int want_stderr)
-{
- /* Set up logging */
- if (!want_stderr) {
-#ifdef USE_SYSLOG_ASYNC
- if (use_syslog_async) {
- openlog_async(syslog_tag, LOG_PID, mu_log_facility);
- gacopyz_set_logger(mf_gacopyz_syslog_async_log_printer);
- } else
-#endif
- {
- openlog(syslog_tag, LOG_PID, mu_log_facility);
- gacopyz_set_logger(gacopyz_syslog_log_printer);
- }
- mu_error_set_print(syslog_error_printer);
- } else {
- gacopyz_set_logger(gacopyz_stderr_log_printer);
- mu_error_set_print(stderr_error_printer);
- }
-}
-
-static int
-stderr_closed_p()
-{
- int fd = dup(0);
- if (fd < 0)
- return 1;
- close(fd);
- return fd <= 2;
-}
-
-static void
-version(FILE *stream, struct argp_state *state)
-{
- mailfromd_version("mailfromd", stream, state);
-}
-
-int
-main(int argc, char **argv)
-{
- int rc;
- int index;
-
-#ifdef ENABLE_NLS
- mu_init_nls();
- setlocale (LC_ALL, "");
- bindtextdomain (PACKAGE, LOCALEDIR);
- textdomain (PACKAGE);
-#endif
-
- MU_AUTH_REGISTER_ALL_MODULES();
- mu_register_all_formats();
- mu_register_all_mailer_formats();
- if (!program_invocation_short_name)
- program_invocation_short_name = argv[0];
- argp_program_version_hook = version;
- yy_flex_debug = 0;
-
- /* Set default logging */
- mu_log_facility = DEFAULT_LOG_FACILITY;
- log_setup(!stderr_closed_p());
-
- init_names();
- init_string_space();
- builtin_setup();
- db_format_setup();
- include_path_setup();
- save_cmdline(argc, argv);
-
- mu_argp_init(program_version, "<" PACKAGE_BUGREPORT ">");
-#if MAILUTILS_VERSION_NUMBER < 1290
- rc = mu_argp_parse(&argp, &argc, &argv, 0, capa, &index, NULL);
-#else
- rc = mu_app_init(&argp, capa, mf_cfg_param, argc, argv, 0, &index,
- NULL);
-#endif
- if (rc)
- exit (EX_CONFIG);
-
- log_setup(log_to_stderr);
-
- argv += index;
- argc -= index;
-
- if (need_config) {
- if (argc) {
- int i, n = -1;
- for (i = 0; i < argc; i++) {
- if (strchr(argv[i], '=') == 0) {
- if (n == -1)
- n = i;
- else {
- mu_error(_("Script file "
- "specified twice "
- "(%s and %s)"),
- argv[n], argv[i]);
- exit(EX_USAGE);
- }
- }
- }
- if (n >= 0) {
- script_file = argv[n];
- memmove(argv + n, argv + n + 1,
- (argc - n + 1) * sizeof argv[0]);
- argc--;
- }
- }
- if (script_file[0] != '/')
- save_cmdline(0, NULL); /* Clear saved command line */
- if (preprocess_option)
- exit(preprocess_input(ext_pp));
- if (parse_program(script_file, script_ydebug))
- exit(EX_CONFIG);
- }
- process_options();
- fixup_state_dir_names();
-
- /* Process some special options */
- if (expire_interval)
- cache_format->expire_interval = negative_expire_interval =
- rate_format->expire_interval = expire_interval;
-
- if (script_dump_tree)
- print_syntax_tree();
- if (script_dump_code)
- print_code();
-
- if (script_dump_xref)
- print_xref();
-
- if (script_dump_macros)
- print_used_macros();
-
- fixup_code();
-
- if (script_check || script_dump_macros
- || script_dump_code || script_dump_tree
- || yy_flex_debug || script_ydebug)
- exit(EX_OK);
-
- free_symbols();
- free_string_space();
-
- switch (mode) {
- case MAILFROMD_COMPACT:
- mailfromd_compact();
- break;
-
- case MAILFROMD_DAEMON:
- if (argc > 0) {
- mu_error(_("Too many arguments"));
- exit(EX_USAGE);
- }
- mailfromd_daemon();
- break;
-
- case MAILFROMD_TEST:
- mailfromd_test(argc, argv);
- break;
-
- case MAILFROMD_DELETE:
- mailfromd_delete(argc, argv);
- break;
-
- case MAILFROMD_LIST:
- mailfromd_list(argc, argv);
- break;
-
- case MAILFROMD_EXPIRE:
- mailfromd_expire();
- break;
-
- case MAILFROMD_SHOW_DEFAULTS:
- mailfromd_show_defaults();
- break;
- }
-
- exit(EX_OK);
-}
-
-void
-xalloc_die()
-{
- parse_error("not enough memory");
- abort();
-}

Return to:

Send suggestions and report system problems to the System administrator.