예제 #1
0
파일: been_here.c 프로젝트: tmtm/postfix
int     been_here(BH_TABLE *dup_filter, const char *fmt,...)
{
    VSTRING *buf = vstring_alloc(100);
    int     status;
    va_list ap;

    /*
     * Construct the string to be checked.
     */
    va_start(ap, fmt);
    vstring_vsprintf(buf, fmt, ap);
    va_end(ap);

    /*
     * Do the duplicate check.
     */
    status = been_here_fixed(dup_filter, vstring_str(buf));

    /*
     * Cleanup.
     */
    vstring_free(buf);
    return (status);
}
예제 #2
0
ARGV   *cleanup_map1n_internal(CLEANUP_STATE *state, const char *addr,
			               MAPS *maps, int propagate)
{
    ARGV   *argv;
    ARGV   *lookup;
    int     count;
    int     i;
    int     arg;
    BH_TABLE *been_here;
    char   *saved_lhs;

    /*
     * Initialize.
     */
    argv = argv_alloc(1);
    argv_add(argv, addr, ARGV_END);
    argv_terminate(argv);
    been_here = been_here_init(0, BH_FLAG_FOLD);

    /*
     * Rewrite the address vector in place. With each map lookup result,
     * split it into separate addresses, then rewrite and flatten each
     * address, and repeat the process. Beware: argv is being changed, so we
     * must index the array explicitly, instead of running along it with a
     * pointer.
     */
#define UPDATE(ptr,new)	do { \
	if (ptr) myfree(ptr); ptr = mystrdup(new); \
    } while (0)
#define STR	vstring_str
#define RETURN(x) do { \
	been_here_free(been_here); return (x); \
    } while (0)
#define UNEXPAND(argv, addr) do { \
	argv_truncate((argv), 0); argv_add((argv), (addr), (char *) 0); \
    } while (0)

    for (arg = 0; arg < argv->argc; arg++) {
	if (argv->argc > var_virt_expan_limit) {
	    msg_warn("%s: unreasonable %s map expansion size for %s -- "
		     "message not accepted, try again later",
		     state->queue_id, maps->title, addr);
	    state->errs |= CLEANUP_STAT_DEFER;
	    UPDATE(state->reason, "4.6.0 Alias expansion error");
	    UNEXPAND(argv, addr);
	    RETURN(argv);
	}
	for (count = 0; /* void */ ; count++) {

	    /*
	     * Don't expand an address that already expanded into itself.
	     */
	    if (been_here_check_fixed(been_here, argv->argv[arg]) != 0)
		break;
	    if (count >= var_virt_recur_limit) {
		msg_warn("%s: unreasonable %s map nesting for %s -- "
			 "message not accepted, try again later",
			 state->queue_id, maps->title, addr);
		state->errs |= CLEANUP_STAT_DEFER;
		UPDATE(state->reason, "4.6.0 Alias expansion error");
		UNEXPAND(argv, addr);
		RETURN(argv);
	    }
	    quote_822_local(state->temp1, argv->argv[arg]);
	    if ((lookup = mail_addr_map(maps, STR(state->temp1), propagate)) != 0) {
		saved_lhs = mystrdup(argv->argv[arg]);
		for (i = 0; i < lookup->argc; i++) {
		    unquote_822_local(state->temp1, lookup->argv[i]);
		    if (i == 0) {
			UPDATE(argv->argv[arg], STR(state->temp1));
		    } else {
			argv_add(argv, STR(state->temp1), ARGV_END);
			argv_terminate(argv);
		    }

		    /*
		     * Allow an address to expand into itself once.
		     */
		    if (strcasecmp(saved_lhs, STR(state->temp1)) == 0)
			been_here_fixed(been_here, saved_lhs);
		}
		myfree(saved_lhs);
		argv_free(lookup);
	    } else if (maps->error != 0) {
		msg_warn("%s: %s map lookup problem for %s -- "
			 "message not accepted, try again later",
			 state->queue_id, maps->title, addr);
		state->errs |= CLEANUP_STAT_WRITE;
		UPDATE(state->reason, "4.6.0 Alias expansion error");
		UNEXPAND(argv, addr);
		RETURN(argv);
	    } else {
		break;
	    }
	}
    }
    RETURN(argv);
}
예제 #3
0
void    cleanup_out_recipient(CLEANUP_STATE *state,
			              const char *dsn_orcpt,
			              int dsn_notify,
			              const char *orcpt,
			              const char *recip)
{
    ARGV   *argv;
    char  **cpp;

    /*
     * XXX Not elegant, but eliminates complexity in the record reading loop.
     */
    if (!var_enable_orcpt)
	orcpt = "";
    if (dsn_orcpt == 0)
	dsn_orcpt = "";

    /*
     * Distinguish between different original recipient addresses that map
     * onto the same mailbox. The recipient will use our original recipient
     * message header to figure things out.
     * 
     * Postfix 2.2 compatibility: when ignoring differences in Postfix original
     * recipient information, also ignore differences in DSN attributes. We
     * do, however, keep the DSN attributes of the recipient that survives
     * duplicate elimination.
     */
#define STREQ(x, y) (strcmp((x), (y)) == 0)

    if ((state->flags & CLEANUP_FLAG_MAP_OK) == 0
	|| cleanup_virt_alias_maps == 0) {
	if ((var_enable_orcpt ?
	     been_here(state->dups, "%s\n%d\n%s\n%s",
		       dsn_orcpt, dsn_notify, orcpt, recip) :
	     been_here_fixed(state->dups, recip)) == 0) {
	    if (dsn_notify)
		cleanup_out_format(state, REC_TYPE_ATTR, "%s=%d",
				   MAIL_ATTR_DSN_NOTIFY, dsn_notify);
	    if (*dsn_orcpt)
		cleanup_out_format(state, REC_TYPE_ATTR, "%s=%s",
				   MAIL_ATTR_DSN_ORCPT, dsn_orcpt);
	    cleanup_out_string(state, REC_TYPE_ORCP, orcpt);
	    cleanup_out_string(state, REC_TYPE_RCPT, recip);
	    state->rcpt_count++;
	}
    }

    /*
     * XXX DSN. RFC 3461 gives us three options for multi-recipient aliases
     * (we're treating single recipient aliases as a special case of
     * multi-recipient aliases, one argument being that it is none of the
     * sender's business).
     * 
     * (a) Don't propagate ENVID, NOTIFY, RET, or ORCPT. If NOTIFY specified
     * SUCCESS, send a "relayed" DSN.
     * 
     * (b) Propagate ENVID, (NOTIFY minus SUCCESS), RET, and ORCPT. If NOTIFY
     * specified SUCCESS, send an "expanded" DSN.
     * 
     * (c) Propagate ENVID, NOTIFY, RET, and ORCPT to one recipient only. Send
     * no DSN.
     * 
     * In all three cases we are modifying at least one NOTIFY value. Either we
     * have to record explicit dsn_notify records, or we must not allow the
     * use of a per-message non-default NOTIFY value that applies to all
     * recipient records.
     * 
     * Alternatives (a) and (c) require that we store explicit per-recipient RET
     * and ENVID records, at least for the recipients that are excluded from
     * RET and ENVID propagation. This means storing explicit ENVID records
     * to indicate that the information does not exist. All this makes
     * alternative (b) more and more attractive. It is no surprise that we
     * use (b) here and in the local delivery agent.
     * 
     * In order to generate a SUCCESS notification from the cleanup server we
     * have to write the trace logfile record now. We're NOT going to flush
     * the trace file from the cleanup server; if we need to write bounce
     * logfile records, and the bounce service fails, we must be able to
     * cancel the entire cleanup request including any success or failure
     * notifications. The queue manager will flush the trace (and bounce)
     * logfile, possibly after it has generated its own success or failure
     * notification records.
     * 
     * Postfix 2.2 compatibility: when ignoring differences in Postfix original
     * recipient information, also ignore differences in DSN attributes. We
     * do, however, keep the DSN attributes of the recipient that survives
     * duplicate elimination.
     */
    else {
	RECIPIENT rcpt;
	DSN     dsn;

	argv = cleanup_map1n_internal(state, recip, cleanup_virt_alias_maps,
				  cleanup_ext_prop_mask & EXT_PROP_VIRTUAL);
	if ((dsn_notify & DSN_NOTIFY_SUCCESS)
	    && (argv->argc > 1 || strcmp(recip, argv->argv[0]) != 0)) {
	    (void) DSN_SIMPLE(&dsn, "2.0.0", "alias expanded");
	    dsn.action = "expanded";
	    RECIPIENT_ASSIGN(&rcpt, 0, dsn_orcpt, dsn_notify, orcpt, recip);
	    cleanup_trace_append(state, &rcpt, &dsn);
	    dsn_notify = (dsn_notify == DSN_NOTIFY_SUCCESS ? DSN_NOTIFY_NEVER :
			  dsn_notify & ~DSN_NOTIFY_SUCCESS);
	}
	for (cpp = argv->argv; *cpp; cpp++) {
	    if ((var_enable_orcpt ?
		 been_here(state->dups, "%s\n%d\n%s\n%s",
			   dsn_orcpt, dsn_notify, orcpt, *cpp) :
		 been_here_fixed(state->dups, *cpp)) == 0) {
		if (dsn_notify)
		    cleanup_out_format(state, REC_TYPE_ATTR, "%s=%d",
				       MAIL_ATTR_DSN_NOTIFY, dsn_notify);
		if (*dsn_orcpt)
		    cleanup_out_format(state, REC_TYPE_ATTR, "%s=%s",
				       MAIL_ATTR_DSN_ORCPT, dsn_orcpt);
		cleanup_out_string(state, REC_TYPE_ORCP, orcpt);
		cleanup_out_string(state, REC_TYPE_RCPT, *cpp);
		state->rcpt_count++;
	    }
	}
	argv_free(argv);
    }
}