diff options
Diffstat (limited to 'src/main.c')
-rw-r--r-- | src/main.c | 398 |
1 files changed, 335 insertions, 63 deletions
@@ -39,2 +39,6 @@ # include <mailutils/argp.h> +typedef struct { + char *file; + int line; +} mu_cfg_locus_t; #else @@ -239,2 +243,17 @@ log_status(sfsistat status, SMFICTX *ctx) +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); +} + @@ -252,4 +271,4 @@ compare_string(const void *item, const void *value) DOMAIN_LIST */ -void -read_domain_file(char *name) +int +read_domain_file(mu_cfg_locus_t *locus, char *name) { @@ -261,5 +280,5 @@ read_domain_file(char *name) 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; } @@ -289,2 +308,3 @@ read_domain_file(char *name) fclose(fp); + return 0; } @@ -329,2 +349,120 @@ host_in_relayed_domain_p(char *client) +/* ************************************************************************ + 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. @@ -506,3 +644,3 @@ load_relay_file(void *item, void *data) { - read_domain_file(item); + read_domain_file(NULL, item); return 0; @@ -646,17 +784,9 @@ 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; @@ -666,27 +796,5 @@ option_source(char *opt, void **pval, char *newval) 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); } @@ -702,20 +810,3 @@ 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); } @@ -1366,2 +1457,182 @@ static struct argp argp = { +/* 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 */ @@ -1773,3 +2044,3 @@ main(int argc, char **argv) MU_AUTH_REGISTER_ALL_MODULES(); - mu_register_all_formats (); + mu_register_all_formats(); mu_register_all_mailer_formats(); @@ -1795,3 +2066,4 @@ main(int argc, char **argv) #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 |