aboutsummaryrefslogtreecommitdiff
path: root/src/main.c
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2007-11-22 12:23:06 +0000
committerSergey Poznyakoff <gray@gnu.org.ua>2007-11-22 12:23:06 +0000
commit080cc8f1c899f91f143694f3a3399a159239496b (patch)
tree8cd38a0e3c0c376a614a60312a9c2e80bae2b845 /src/main.c
parent861696aa40909d5c11ab4876b716d48fef73a49d (diff)
downloadmailfromd-080cc8f1c899f91f143694f3a3399a159239496b.tar.gz
mailfromd-080cc8f1c899f91f143694f3a3399a159239496b.tar.bz2
* src/main.c: Implement MU configuration statements.
* tests/atlocal.in (MFOPTS): Ignore site-wide and per-user configuration files. * doc/mailfromd.texi: Document sieve interface. git-svn-id: file:///svnroot/mailfromd/trunk@1533 7a8a7f39-df28-0410-adc6-e0d955640f24
Diffstat (limited to 'src/main.c')
-rw-r--r--src/main.c398
1 files changed, 335 insertions, 63 deletions
diff --git a/src/main.c b/src/main.c
index 80c81226..3798ca3f 100644
--- a/src/main.c
+++ b/src/main.c
@@ -34,12 +34,16 @@
#include <arpa/inet.h>
#include <netdb.h>
#include <mailutils/mailutils.h>
#if MAILUTILS_VERSION_NUMBER < 1290
# include <mailutils/argp.h>
+typedef struct {
+ char *file;
+ int line;
+} mu_cfg_locus_t;
#else
# include <mailutils/libargp.h>
#endif
#include "mailfromd.h"
#include "syslog_async.h"
@@ -234,12 +238,27 @@ log_status(sfsistat status, SMFICTX *ctx)
logmsg(LOG_INFO,
"%sstatus %d",
mailfromd_msgid(ctx), status);
}
}
+static void
+mf_error_on_locus(mu_cfg_locus_t *locus, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (locus) {
+ char *newfmt = NULL;
+ asprintf(&newfmt, "%s:%d: %s", locus->file, locus->line, fmt);
+ mu_verror(newfmt, ap);
+ } else
+ mu_verror(fmt, ap);
+ va_end(ap);
+}
+
/* Sendmail class file support */
static mu_list_t domain_list;
int
@@ -247,24 +266,24 @@ 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 */
-void
-read_domain_file(char *name)
+int
+read_domain_file(mu_cfg_locus_t *locus, 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;
+ mf_error_on_locus(locus, _("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);
}
@@ -284,12 +303,13 @@ read_domain_file(char *name)
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)
{
@@ -324,12 +344,130 @@ host_in_relayed_domain_p(char *client)
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_cfg_locus_t *locus, 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(locus,
+ _("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(locus, _("Unknown group: %s"), arg);
+ return 1;
+ }
+ return 0;
+}
+
+static int
+mf_option_mailfrom(mu_cfg_locus_t *locus, char *arg)
+{
+ int rc;
+ mu_address_t addr;
+
+ rc = mu_address_create(&addr, arg);
+ if (rc) {
+ mf_error_on_locus(locus, _("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_cfg_locus_t *locus, char *arg)
+{
+ struct stat st;
+ if (stat(arg, &st)) {
+ mf_error_on_locus(locus, _("Cannot stat file `%s': %s"),
+ arg,
+ mu_strerror(errno));
+ return 1;
+ }
+ if (!S_ISDIR(st.st_mode)) {
+ mf_error_on_locus(locus, _("`%s' is not a directory"), arg);
+ return 1;
+ }
+ if (arg[0] != '/') {
+ mf_error_on_locus(locus,
+ _("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_cfg_locus_t *locus, 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(locus, _("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.
@@ -501,13 +639,13 @@ set_response_timeout(void *value)
free(value);
}
static int
load_relay_file(void *item, void *data)
{
- read_domain_file(item);
+ read_domain_file(NULL, item);
return 0;
}
static void
set_relay(void *value)
{
@@ -641,86 +779,39 @@ option_relay(char *opt, void **pval, char *newval)
return 0;
}
static int
option_source(char *opt, void **pval, char *newval)
{
- unsigned long address = inet_addr (newval);
- if (address == INADDR_NONE) {
- struct hostent *phe = gethostbyname (newval);
- if (!phe) {
- mu_error(_("Cannot resolve `%s'"), newval);
- return 1;
- }
- address = *(((unsigned long **) phe->h_addr_list)[0]);
- }
+ unsigned long address;
+
+ if (mf_option_source_ip(NULL, newval, &address))
+ return 1;
- if (*pval == 0) {
- *pval = malloc (sizeof address);
- if (!*pval)
- return 1;
- }
+ if (*pval == 0)
+ *pval = xmalloc (sizeof address);
*(unsigned long*)*pval = address;
return 0;
}
static int
-gid_comp(const void *item, const void *data)
-{
- return (gid_t) item != (gid_t) data;
-}
-
-static int
option_group(char *opt, void **pval, char *newval)
{
- struct group *group = getgrnam(newval);
- if (group) {
- if (!retain_groups) {
- int rc = mu_list_create(&retain_groups);
- if (rc) {
- mu_error(_("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 {
- mu_error(_("Unknown group: %s"), newval);
- return 1;
- }
- return 0;
+ return mf_option_group(NULL, newval);
}
void
set_state_directory(void *value)
{
/* nothing */
}
int
option_state_directory(char *opt, void **pval, char *newval)
{
- struct stat st;
- if (stat(newval, &st)) {
- mu_error(_("Cannot stat file `%s': %s"),
- newval,
- mu_strerror(errno));
- return 1;
- }
- if (!S_ISDIR(st.st_mode)) {
- mu_error(_("`%s' is not a directory"), newval);
- return 1;
- }
- if (newval[0] != '/') {
- mu_error(_("State directory `%s' is not an absolute file name"),
- newval);
- return 1;
- }
- mailfromd_state_dir = xstrdup(newval);
- return 0;
+ return mf_option_state_directory(NULL, newval);
}
struct option_cache {
char *name;
void *value;
int (*handler)(char *opt, void **pval, char *newval);
@@ -1361,12 +1452,192 @@ static struct argp argp = {
NULL,
NULL,
NULL
};
+/* Mailutils-2.0 configuration */
+#if MAILUTILS_VERSION_NUMBER >= 1290
+int
+cb_timeout(time_t *pinterval, mu_cfg_locus_t *locus, void *data, char *arg)
+{
+ const char *endp;
+ if (parse_time_interval(arg, pinterval, &endp)) {
+ mf_error_on_locus(locus,
+ _("unrecognized time format (near `%s')"),
+ endp);
+ return 1;
+ }
+ return 0;
+}
+
+int
+cb_milter_timeout(mu_cfg_locus_t *locus, void *data, char *arg)
+{
+ time_t interval;
+
+ if (cb_timeout(&interval, locus, data, arg))
+ return 1;
+ if (smfi_settimeout(interval) == MI_FAILURE) {
+ mf_error_on_locus(locus,
+ _("%s:%d: Invalid milter timeout: %lu"),
+ (unsigned long) interval);
+ exit(EX_USAGE);
+ }
+
+ return 0;
+}
+
+int
+cb_io_timeout(mu_cfg_locus_t *locus, void *data, char *arg)
+{
+ if (cb_timeout(&io_timeout, locus, data, arg))
+ return 1;
+ return 0;
+}
+
+int
+cb_connect_timeout(mu_cfg_locus_t *locus, void *data, char *arg)
+{
+ if (cb_timeout(&connect_timeout, locus, data, arg))
+ return 1;
+ return 0;
+}
+
+int
+cb_initial_response_timeout(mu_cfg_locus_t *locus, void *data, char *arg)
+{
+ if (cb_timeout(&response_timeout, locus, data, arg))
+ return 1;
+ return 0;
+}
+
+int
+cb_lock_retry_timeout(mu_cfg_locus_t *locus, void *data, char *arg)
+{
+ if (cb_timeout(&lock_retry_timeout_option, locus, data, arg))
+ return 1;
+ return 0;
+}
+
+int
+cb_set_variable(mu_cfg_locus_t *locus, void *data, char *arg)
+{
+ char *p, *value;
+ char *tmp = NULL;
+
+ for (p = arg; !(*p == ' ' || *p == '\t'); p++)
+ if (!*p) {
+ mf_error_on_locus(locus, _("missing value"));
+ return 1;
+ }
+
+ for (; *p == ' ' || *p == '\t'; p++)
+ if (!*p) {
+ mf_error_on_locus(locus, _("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_cfg_locus_t *locus, void *data, char *arg)
+{
+ defer_initialize_variable("ehlo_domain", arg);
+ return 0;
+}
+
+int
+cb_mail_from_address(mu_cfg_locus_t *locus, void *data, char *arg)
+{
+ return mf_option_mailfrom(locus, arg);
+}
+
+int
+cb_debug(mu_cfg_locus_t *locus, void *data, char *arg)
+{
+ debug_parse_spec(arg);
+ return 0;
+}
+
+/* See also option_group. */
+int
+cb_group(mu_cfg_locus_t *locus, void *data, char *arg)
+{
+ return mf_option_group(locus, arg);
+}
+
+int
+cb_state_directory(mu_cfg_locus_t *locus, void *data, char *arg)
+{
+ return mf_option_state_directory(locus, arg);
+}
+
+int
+cb_relay_file(mu_cfg_locus_t *locus, void *data, char *arg)
+{
+ return read_domain_file(locus, arg);
+}
+
+int
+cb_source_ip(mu_cfg_locus_t *locus, void *data, char *arg)
+{
+ return mf_option_source_ip(locus, arg, &source_address);
+}
+
+int
+cb_include_path(mu_cfg_locus_t *locus, 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[] = {
+ { "connect-timeout", mu_cfg_callback, NULL, cb_connect_timeout },
+ { "debug", mu_cfg_callback, NULL, cb_debug },
+ { "ehlo-domain", mu_cfg_callback, NULL, cb_ehlo_domain },
+ { "group", mu_cfg_callback, NULL, cb_group },
+ { "include-path", mu_cfg_callback, NULL, cb_include_path },
+ { "initial-response-timeout", mu_cfg_callback, NULL,
+ cb_initial_response_timeout },
+ { "io-timeout", mu_cfg_callback, NULL, cb_io_timeout },
+ { "lock-retry-count", mu_cfg_size, &lock_retry_count_option },
+ { "lock-retry-timeout", mu_cfg_callback, NULL,
+ cb_lock_retry_timeout },
+ { "mail-from-address", mu_cfg_callback, NULL, cb_mail_from_address },
+ { "milter-timeout", mu_cfg_callback, NULL, cb_milter_timeout },
+ { "pidfile", mu_cfg_string, &pidfile },
+ { "relay-file", mu_cfg_callback, NULL, cb_relay_file },
+ { "setvar", mu_cfg_callback, NULL, cb_set_variable },
+ { "script-file", mu_cfg_string, &script_file },
+ { "source-info", mu_cfg_bool, &source_info_option },
+ /* FIXME: Could have used mu_cfg_ipv4 here, but... */
+ { "source-ip", mu_cfg_callback, NULL, cb_source_ip },
+ { "stack-trace", mu_cfg_bool, &stack_trace_option },
+ { "state-directory", mu_cfg_callback, NULL, cb_state_directory },
+ { "user", mu_cfg_string, &user },
+ { NULL }
+};
+#endif
+
+
/* Auxiliary functions */
/* Switch to the given UID/GID */
int
switch_to_privs(uid_t uid, gid_t gid)
{
@@ -1768,13 +2039,13 @@ main(int argc, char **argv)
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
#endif
MU_AUTH_REGISTER_ALL_MODULES();
- mu_register_all_formats ();
+ 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;
@@ -1790,13 +2061,14 @@ main(int argc, char **argv)
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, NULL, argc, argv, 0, &index, NULL);
+ 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);

Return to:

Send suggestions and report system problems to the System administrator.