<b>alias</b><i>_</i><b>maps</b>
List of alias databases.
- <b>local</b><i>_</i><b>command</b><i>_</i><b>shell</b>
- Shell to use for external command execution (for
- example, /some/where/smrsh -c). When a shell is
- specified, it is invoked even when the command con-
- tains no shell built-in commands or meta
+ <b>forward</b><i>_</i><b>path</b>
+ Search list for .forward files. The following
+ macros are recognized: <b>$home</b> (home directory),
+ <b>$user</b> (login name), <b>$extension</b> (address extension),
+ <b>$recipient</b><i>_</i><b>delimiter</b> (address extension delimiter).
LOCAL(8) LOCAL(8)
- characters.
+ <b>local</b><i>_</i><b>command</b><i>_</i><b>shell</b>
+ Shell to use for external command execution (for
+ example, /some/where/smrsh -c). When a shell is
+ specified, it is invoked even when the command con-
+ tains no shell built-in commands or meta charac-
+ ters.
<b>owner</b><i>_</i><b>request</b><i>_</i><b>special</b>
Give special treatment to <b>owner-</b><i>xxx</i> and <i>xxx</i><b>-request</b>
Time in seconds between successive attempts to
acquire an exclusive lock.
- <b>stale</b><i>_</i><b>lock</b><i>_</i><b>time</b>
- Limit the time after which a stale lock is removed.
-
-
-
5
LOCAL(8) LOCAL(8)
+ <b>stale</b><i>_</i><b>lock</b><i>_</i><b>time</b>
+ Limit the time after which a stale lock is removed.
+
<b>Resource</b> <b>controls</b>
<b>command</b><i>_</i><b>time</b><i>_</i><b>limit</b>
Limit the amount of time for delivery to external
syslogd(8) system logging
<a href="qmgr.8.html">qmgr(8)</a> queue manager
-<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
- software.
LOCAL(8) LOCAL(8)
+<b>LICENSE</b>
+ The Secure Mailer license must be distributed with this
+ software.
+
<b>AUTHOR(S)</b>
Wietse Venema
IBM T.J. Watson Research
-
-
-
-
/* int *statusp;
/* DESCRIPTION
/* deliver_dotforward() delivers a message to the destinations
-/* listed in a recipient's $HOME/.forward file. The result is
-/* zero when no acceptable $HOME/.forward file was found, or when
+/* listed in a recipient's .forward file(s) as specified through
+/* the forward_path configuration parameter. The result is
+/* zero when no acceptable .forward file was found, or when
/* a recipient is listed in her own .forward file.
/*
-/* When mail is sent to an extended address (e.g., user+foo),
-/* the address extension is appended to the .forward file name
-/* (e.g., .forward+foo). When that file does not exist, .forward
-/* is used instead.
-/*
/* Arguments:
/* .IP state
/* Message delivery attributes (sender, recipient etc.).
#include <iostuff.h>
#include <stringops.h>
#include <mymalloc.h>
+#include <mac_parse.h>
/* Global library. */
#include <bounce.h>
#include <been_here.h>
#include <mail_params.h>
+#include <config.h>
/* Application-specific. */
#define NO 0
#define YES 1
+ /*
+ * A little helper structure for message-specific context.
+ */
+typedef struct {
+ int failures; /* $name not available */
+ struct mypasswd *pwd; /* recipient */
+ char *extension; /* address extension */
+ VSTRING *path; /* result */
+} FW_CONTEXT;
+
+/* dotforward_parse_callback - callback for mac_parse */
+
+static void dotforward_parse_callback(int type, VSTRING *buf, char *context)
+{
+ char *myname = "dotforward_parse_callback";
+ FW_CONTEXT *fw_context = (FW_CONTEXT *) context;
+ char *ptr;
+
+ /*
+ * Find out what data to substitute.
+ */
+ if (type == MAC_PARSE_VARNAME) {
+ if (strcmp(vstring_str(buf), "home") == 0)
+ ptr = fw_context->pwd->pw_dir;
+ else if (strcmp(vstring_str(buf), "user") == 0)
+ ptr = fw_context->pwd->pw_name;
+ else if (strcmp(vstring_str(buf), "extension") == 0)
+ ptr = fw_context->extension;
+ else if (strcmp(vstring_str(buf), "recipient_delimiter") == 0)
+ ptr = var_rcpt_delim;
+ else
+ msg_fatal("unknown macro $%s in %s", vstring_str(buf),
+ VAR_FORWARD_PATH);
+ } else {
+ ptr = vstring_str(buf);
+ }
+
+ /*
+ * Append the data, or record that the data was not available.
+ */
+ if (msg_verbose)
+ msg_info("%s: %s = %s", myname, vstring_str(buf),
+ ptr ? ptr : "(unavailable)");
+ if (ptr == 0) {
+ fw_context->failures++;
+ } else {
+ vstring_strcat(fw_context->path, ptr);
+ }
+}
+
/* deliver_dotforward - expand contents of .forward file */
int deliver_dotforward(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
int forward_found = NO;
int lookup_status;
int addr_count;
- char *extension;
+ char *saved_forward_path;
+ char *lhs;
+ char *next;
+ const char *forward_path;
+ FW_CONTEXT fw_context;
/*
* Make verbose logging easier to understand.
if (msg_verbose)
MSG_LOG_STATE(myname, state);
+ /*
+ * Skip this module if per-user forwarding is disabled. XXX We need to
+ * extend the config_XXX() interface to request no expansion of $names in
+ * the given value or in the default value.
+ */
+ if ((forward_path = config_lookup(VAR_FORWARD_PATH)) == 0)
+ forward_path = DEF_FORWARD_PATH;
+ if (*forward_path == 0)
+ return (NO);
+
/*
* DUPLICATE/LOOP ELIMINATION
*
* Assume that usernames do not have file system meta characters. Open
* the .forward file as the user. Ignore files that aren't regular files,
* files that are owned by the wrong user, or files that have world write
- * permission enabled. We take no special precautions to deal with home
- * directories imported via NFS, because mailbox and .forward files
- * should always be local to the host running the delivery process.
- * Anything else is just asking for trouble when a server goes down
- * (either the mailbox server or the home directory server).
- *
- * With mail to user+foo, try ~/.forward+foo before ~/.forward. Ignore foo
- * when it contains '/' or when forward+foo does not exist.
+ * permission enabled.
*/
#define STR(x) vstring_str(x)
status = 0;
path = vstring_alloc(100);
- extension = state.msg_attr.extension;
- if (extension && strchr(extension, '/')) {
- msg_warn("%s: address with illegal extension: %s",
- state.msg_attr.queue_id, state.msg_attr.recipient);
- extension = 0;
- }
- if (extension != 0) {
- vstring_sprintf(path, "%s/.forward%c%s", mypwd->pw_dir,
- var_rcpt_delim[0], extension);
- if ((lookup_status = lstat_as(STR(path), &st,
- usr_attr.uid, usr_attr.gid)) < 0)
- extension = 0;
- }
- if (extension == 0) {
- vstring_sprintf(path, "%s/.forward", mypwd->pw_dir);
- lookup_status = lstat_as(STR(path), &st, usr_attr.uid, usr_attr.gid);
+ saved_forward_path = mystrdup(forward_path);
+ next = saved_forward_path;
+
+ fw_context.pwd = mypwd;
+ fw_context.extension = state.msg_attr.extension;
+ fw_context.path = path;
+
+ lookup_status = -1;
+
+ while ((lhs = mystrtok(&next, ", \t\r\n")) != 0) {
+ fw_context.failures = 0;
+ VSTRING_RESET(path);
+ mac_parse(lhs, dotforward_parse_callback, (char *) &fw_context);
+ if (fw_context.failures == 0) {
+ lookup_status = lstat_as(STR(path), &st,
+ usr_attr.uid, usr_attr.gid);
+ if (msg_verbose)
+ msg_info("%s: path %s status %d", myname,
+ STR(path), lookup_status);
+ if (lookup_status >= 0)
+ break;
+ }
}
+
if (lookup_status >= 0) {
if (S_ISREG(st.st_mode) == 0) {
msg_warn("file %s is not a regular file", STR(path));
* Clean up.
*/
vstring_free(path);
+ myfree(saved_forward_path);
mypwfree(mypwd);
*statusp = status;
/* .fi
/* .IP \fBalias_maps\fR
/* List of alias databases.
+/* .IP \fBforward_path\fR
+/* Search list for .forward files. The following macros are recognized:
+/* \fB$home\fR (home directory), \fB$user\fR (login name),
+/* \fB$extension\fR (address extension), \fB$recipient_delimiter\fR
+/* (address extension delimiter).
/* .IP \fBlocal_command_shell\fR
/* Shell to use for external command execution (for example,
/* /some/where/smrsh -c).
char *var_mail_spool_dir;
char *var_mailbox_transport;
char *var_fallback_transport;
+char *var_forward_path;
int local_cmd_deliver_mask;
int local_file_deliver_mask;
0,
};
+ /*
+ * XXX We need to extend the config_XXX() interface to request no $name
+ * expansion in a given value or in the default value.
+ */
+ static CONFIG_STR_TABLE straight_str_table[] = {
+ VAR_FORWARD_PATH, DEF_FORWARD_PATH, &var_forward_path, 0, 0,
+ 0,
+ };
+
single_server_main(argc, argv, local_service,
MAIL_SERVER_INT_TABLE, int_table,
MAIL_SERVER_STR_TABLE, str_table,