示例#1
0
static int deliver_switch(LOCAL_STATE state, USER_ATTR usr_attr)
{
    const char *myname = "deliver_switch";
    int     status = 0;
    struct stat st;
    struct mypasswd *mypwd;

    /*
     * Make verbose logging easier to understand.
     */
    state.level++;
    if (msg_verbose)
	MSG_LOG_STATE(myname, state);


    /*
     * \user is special: it means don't do any alias or forward expansion.
     * 
     * XXX This code currently does not work due to revision of the RFC822
     * address parser. \user should be permitted only in locally specified
     * aliases, includes or forward files.
     * 
     * XXX Should test for presence of user home directory.
     */
    if (state.msg_attr.rcpt.address[0] == '\\') {
	state.msg_attr.rcpt.address++, state.msg_attr.local++, state.msg_attr.user++;
	if (deliver_mailbox(state, usr_attr, &status) == 0)
	    status = deliver_unknown(state, usr_attr);
	return (status);
    }

    /*
     * Otherwise, alias expansion has highest precedence. First look up the
     * full localpart, then the bare user. Obey the address extension
     * propagation policy.
     */
    state.msg_attr.unmatched = 0;
    if (deliver_alias(state, usr_attr, state.msg_attr.local, &status))
	return (status);
    if (state.msg_attr.extension != 0) {
	if (local_ext_prop_mask & EXT_PROP_ALIAS)
	    state.msg_attr.unmatched = state.msg_attr.extension;
	if (deliver_alias(state, usr_attr, state.msg_attr.user, &status))
	    return (status);
	state.msg_attr.unmatched = state.msg_attr.extension;
    }

    /*
     * Special case for mail locally forwarded or aliased to a different
     * local address. Resubmit the message via the cleanup service, so that
     * each recipient gets a separate delivery queue file status record in
     * the new queue file. The downside of this approach is that mutually
     * recursive .forward files cause a mail forwarding loop. Fortunately,
     * the loop can be broken by the use of the Delivered-To: message header.
     * 
     * The code below must not trigger on mail sent to an alias that has no
     * owner- companion, so that mail for an alias first.last->username is
     * delivered directly, instead of going through username->first.last
     * canonical mappings in the cleanup service. The downside of this
     * approach is that recipients in the expansion of an alias without
     * owner- won't have separate delivery queue file status records, because
     * for them, the message won't be resubmitted as a new queue file.
     * 
     * Do something sensible on systems that receive mail for multiple domains,
     * such as primary.name and secondary.name. Don't resubmit the message
     * when mail for `[email protected]' is delivered to a .forward file
     * that lists `user' or `[email protected]'. We already know that the
     * recipient domain is local, so we only have to compare local parts.
     */
    if (state.msg_attr.owner != 0
	&& strcasecmp(state.msg_attr.owner, state.msg_attr.user) != 0)
	return (deliver_indirect(state));

    /*
     * Always forward recipients in :include: files.
     */
    if (state.msg_attr.exp_type == EXPAND_TYPE_INCL)
	return (deliver_indirect(state));

    /*
     * Delivery to local user. First try expansion of the recipient's
     * $HOME/.forward file, then mailbox delivery. Back off when the user's
     * home directory does not exist.
     */
    if (var_stat_home_dir
	&& (mypwd = mypwnam(state.msg_attr.user)) != 0
	&& stat_as(mypwd->pw_dir, &st, mypwd->pw_uid, mypwd->pw_gid) < 0) {
	dsb_simple(state.msg_attr.why, "4.3.0",
		   "cannot access home directory %s: %m", mypwd->pw_dir);
	return (defer_append(BOUNCE_FLAGS(state.request),
			     BOUNCE_ATTR(state.msg_attr)));
    }
    if (deliver_dotforward(state, usr_attr, &status) == 0
	&& deliver_mailbox(state, usr_attr, &status) == 0)
	status = deliver_unknown(state, usr_attr);
    return (status);
}
示例#2
0
int     deliver_resolve_tree(LOCAL_STATE state, USER_ATTR usr_attr, TOK822 *addr)
{
    const char *myname = "deliver_resolve_tree";
    RESOLVE_REPLY reply;
    int     status;
    ssize_t ext_len;
    char   *ratsign;
    int     rcpt_delim;

    /*
     * Make verbose logging easier to understand.
     */
    state.level++;
    if (msg_verbose)
	MSG_LOG_STATE(myname, state);

    /*
     * Initialize.
     */
    resolve_clnt_init(&reply);

    /*
     * Rewrite the address to canonical form, just like the cleanup service
     * does. Then, resolve the address to (transport, nexhop, recipient),
     * just like the queue manager does. The only part missing here is the
     * virtual address substitution. Message forwarding fixes most of that.
     */
    tok822_rewrite(addr, REWRITE_CANON);
    tok822_resolve(addr, &reply);

    /*
     * First, a healthy portion of error handling.
     */
    if (reply.flags & RESOLVE_FLAG_FAIL) {
	dsb_simple(state.msg_attr.why, "4.3.0", "address resolver failure");
	status = defer_append(BOUNCE_FLAGS(state.request),
			      BOUNCE_ATTR(state.msg_attr));
    } else if (reply.flags & RESOLVE_FLAG_ERROR) {
	dsb_simple(state.msg_attr.why, "5.1.3",
		   "bad recipient address syntax: %s", STR(reply.recipient));
	status = bounce_append(BOUNCE_FLAGS(state.request),
			       BOUNCE_ATTR(state.msg_attr));
    } else {

	/*
	 * Splice in the optional unmatched address extension.
	 */
	if (state.msg_attr.unmatched) {
	    rcpt_delim = state.msg_attr.local[strlen(state.msg_attr.user)];
	    if ((ratsign = strrchr(STR(reply.recipient), '@')) == 0) {
		VSTRING_ADDCH(reply.recipient, rcpt_delim);
		vstring_strcat(reply.recipient, state.msg_attr.unmatched);
	    } else {
		ext_len = strlen(state.msg_attr.unmatched);
		VSTRING_SPACE(reply.recipient, ext_len + 2);
		if ((ratsign = strrchr(STR(reply.recipient), '@')) == 0)
		    msg_panic("%s: recipient @ botch", myname);
		memmove(ratsign + ext_len + 1, ratsign, strlen(ratsign) + 1);
		*ratsign = rcpt_delim;
		memcpy(ratsign + 1, state.msg_attr.unmatched, ext_len);
		VSTRING_SKIP(reply.recipient);
	    }
	}
	state.msg_attr.rcpt.address = STR(reply.recipient);

	/*
	 * Delivery to a local or non-local address. For a while there was
	 * some ugly code to force local recursive alias expansions on a host
	 * with no authority over the local domain, but that code was just
	 * too unclean.
	 */
	if (strcmp(state.msg_attr.relay, STR(reply.transport)) == 0) {
	    status = deliver_recipient(state, usr_attr);
	} else {
	    status = deliver_indirect(state);
	}
    }

    /*
     * Cleanup.
     */
    resolve_clnt_free(&reply);

    return (status);
}