コード例 #1
0
ファイル: smtpd_resolve.c プロジェクト: DabeDotCom/postfix
static void *resolve_pagein(const char *addr, void *unused_context)
{
    static VSTRING *query;
    RESOLVE_REPLY *reply;
    char   *tmp;

    /*
     * Initialize on the fly.
     */
    if (query == 0)
	query = vstring_alloc(10);

    /*
     * Initialize.
     */
    reply = (RESOLVE_REPLY *) mymalloc(sizeof(*reply));
    resolve_clnt_init(reply);

    /*
     * Resolve the address.
     */
    rewrite_clnt_internal(MAIL_ATTR_RWR_LOCAL, addr, query);
    resolve_clnt_query(STR(query), reply);
    tmp = mystrdup(STR(reply->recipient));
    casefold(reply->recipient, tmp);		/* XXX */
    myfree(tmp);

    /*
     * Save the result.
     */
    return ((void *) reply);
}
コード例 #2
0
ファイル: qmgr_message.c プロジェクト: hiroya/postfix
static void qmgr_message_resolve(QMGR_MESSAGE *message)
{
    static ARGV *defer_xport_argv;
    RECIPIENT_LIST list = message->rcpt_list;
    RECIPIENT *recipient;
    QMGR_TRANSPORT *transport = 0;
    QMGR_QUEUE *queue = 0;
    RESOLVE_REPLY reply;
    VSTRING *queue_name;
    char   *at;
    char  **cpp;
    char   *nexthop;
    ssize_t len;
    int     status;
    DSN     dsn;
    MSG_STATS stats;
    DSN    *saved_dsn;

#define STREQ(x,y)	(strcmp(x,y) == 0)
#define STR		vstring_str
#define LEN		VSTRING_LEN

    resolve_clnt_init(&reply);
    queue_name = vstring_alloc(1);
    for (recipient = list.info; recipient < list.info + list.len; recipient++) {

	/*
	 * Redirect overrides all else. But only once (per entire message).
	 * For consistency with the remainder of Postfix, rewrite the address
	 * to canonical form before resolving it.
	 */
	if (message->redirect_addr) {
	    if (recipient > list.info) {
		recipient->u.queue = 0;
		continue;
	    }
	    message->rcpt_offset = 0;
	    message->rcpt_unread = 0;

	    rewrite_clnt_internal(REWRITE_CANON, message->redirect_addr,
				  reply.recipient);
	    RECIPIENT_UPDATE(recipient->address, STR(reply.recipient));
	    if (qmgr_resolve_one(message, recipient,
				 recipient->address, &reply) < 0)
		continue;
	    if (!STREQ(recipient->address, STR(reply.recipient)))
		RECIPIENT_UPDATE(recipient->address, STR(reply.recipient));
	}

	/*
	 * Content filtering overrides the address resolver.
	 * 
	 * XXX Bypass content_filter inspection for user-generated probes
	 * (sendmail -bv). MTA-generated probes never have the "please filter
	 * me" bits turned on, but we handle them here anyway for the sake of
	 * future proofing.
	 */
#define FILTER_WITHOUT_NEXTHOP(filter, next) \
	(((next) = split_at((filter), ':')) == 0 || *(next) == 0)

#define RCPT_WITHOUT_DOMAIN(rcpt, next) \
	((next = strrchr(rcpt, '@')) == 0 || *++(next) == 0)

	else if (message->filter_xport
		 && (message->tflags & DEL_REQ_TRACE_ONLY_MASK) == 0) {
	    reply.flags = 0;
	    vstring_strcpy(reply.transport, message->filter_xport);
	    if (FILTER_WITHOUT_NEXTHOP(STR(reply.transport), nexthop)
		&& *(nexthop = var_def_filter_nexthop) == 0
		&& RCPT_WITHOUT_DOMAIN(recipient->address, nexthop))
		nexthop = var_myhostname;
	    vstring_strcpy(reply.nexthop, nexthop);
	    vstring_strcpy(reply.recipient, recipient->address);
	}

	/*
	 * Resolve the destination to (transport, nexthop, address). The
	 * result address may differ from the one specified by the sender.
	 */
	else {
	    if (qmgr_resolve_one(message, recipient,
				 recipient->address, &reply) < 0)
		continue;
	    if (!STREQ(recipient->address, STR(reply.recipient)))
		RECIPIENT_UPDATE(recipient->address, STR(reply.recipient));
	}

	/*
	 * Bounce null recipients. This should never happen, but is most
	 * likely the result of a fault in a different program, so aborting
	 * the queue manager process does not help.
	 */
	if (recipient->address[0] == 0) {
	    QMGR_REDIRECT(&reply, MAIL_SERVICE_ERROR,
			  "5.1.3 null recipient address");
	}

	/*
	 * Discard mail to the local double bounce address here, so this
	 * system can run without a local delivery agent. They'd still have
	 * to configure something for mail directed to the local postmaster,
	 * though, but that is an RFC requirement anyway.
	 * 
	 * XXX This lookup should be done in the resolver, and the mail should
	 * be directed to a general-purpose null delivery agent.
	 */
	if (reply.flags & RESOLVE_CLASS_LOCAL) {
	    at = strrchr(STR(reply.recipient), '@');
	    len = (at ? (at - STR(reply.recipient))
		   : strlen(STR(reply.recipient)));
	    if (strncasecmp(STR(reply.recipient), var_double_bounce_sender,
			    len) == 0
		&& !var_double_bounce_sender[len]) {
		status = sent(message->tflags, message->queue_id,
			      QMGR_MSG_STATS(&stats, message), recipient,
			      "none", DSN_SIMPLE(&dsn, "2.0.0",
			"undeliverable postmaster notification discarded"));
		if (status == 0) {
		    deliver_completed(message->fp, recipient->offset);
#if 0
		    /* It's the default verification probe sender address. */
		    msg_warn("%s: undeliverable postmaster notification discarded",
			     message->queue_id);
#endif
		} else
		    message->flags |= status;
		continue;
	    }
	}

	/*
	 * Optionally defer deliveries over specific transports, unless the
	 * restriction is lifted temporarily.
	 */
	if (*var_defer_xports && (message->qflags & QMGR_FLUSH_DFXP) == 0) {
	    if (defer_xport_argv == 0)
		defer_xport_argv = argv_split(var_defer_xports, CHARS_COMMA_SP);
	    for (cpp = defer_xport_argv->argv; *cpp; cpp++)
		if (strcmp(*cpp, STR(reply.transport)) == 0)
		    break;
	    if (*cpp) {
		QMGR_REDIRECT(&reply, MAIL_SERVICE_RETRY,
			      "4.3.2 deferred transport");
	    }
	}

	/*
	 * Look up or instantiate the proper transport.
	 */
	if (transport == 0 || !STREQ(transport->name, STR(reply.transport))) {
	    if ((transport = qmgr_transport_find(STR(reply.transport))) == 0)
		transport = qmgr_transport_create(STR(reply.transport));
	    queue = 0;
	}

	/*
	 * This message is being flushed. If need-be unthrottle the
	 * transport.
	 */
	if ((message->qflags & QMGR_FLUSH_EACH) != 0
	    && QMGR_TRANSPORT_THROTTLED(transport))
	    qmgr_transport_unthrottle(transport);

	/*
	 * This transport is dead. Defer delivery to this recipient.
	 */
	if (QMGR_TRANSPORT_THROTTLED(transport)) {
	    saved_dsn = transport->dsn;
	    if ((transport = qmgr_error_transport(MAIL_SERVICE_RETRY)) != 0) {
		nexthop = qmgr_error_nexthop(saved_dsn);
		vstring_strcpy(reply.nexthop, nexthop);
		myfree(nexthop);
		queue = 0;
	    } else {
		qmgr_defer_recipient(message, recipient, saved_dsn);
		continue;
	    }
	}

	/*
	 * The nexthop destination provides the default name for the
	 * per-destination queue. When the delivery agent accepts only one
	 * recipient per delivery, give each recipient its own queue, so that
	 * deliveries to different recipients of the same message can happen
	 * in parallel, and so that we can enforce per-recipient concurrency
	 * limits and prevent one recipient from tying up all the delivery
	 * agent resources. We use recipient@nexthop as queue name rather
	 * than the actual recipient domain name, so that one recipient in
	 * multiple equivalent domains cannot evade the per-recipient
	 * concurrency limit. Split the address on the recipient delimiter if
	 * one is defined, so that extended addresses don't get extra
	 * delivery slots.
	 * 
	 * Fold the result to lower case so that we don't have multiple queues
	 * for the same name.
	 * 
	 * Important! All recipients in a queue must have the same nexthop
	 * value. It is OK to have multiple queues with the same nexthop
	 * value, but only when those queues are named after recipients.
	 * 
	 * The single-recipient code below was written for local(8) like
	 * delivery agents, and assumes that all domains that deliver to the
	 * same (transport + nexthop) are aliases for $nexthop. Delivery
	 * concurrency is changed from per-domain into per-recipient, by
	 * changing the queue name from nexthop into localpart@nexthop.
	 * 
	 * XXX This assumption is incorrect when different destinations share
	 * the same (transport + nexthop). In reality, such transports are
	 * rarely configured to use single-recipient deliveries. The fix is
	 * to decouple the per-destination recipient limit from the
	 * per-destination concurrency.
	 */
	vstring_strcpy(queue_name, STR(reply.nexthop));
	if (strcmp(transport->name, MAIL_SERVICE_ERROR) != 0
	    && strcmp(transport->name, MAIL_SERVICE_RETRY) != 0
	    && transport->recipient_limit == 1) {
	    /* Copy the recipient localpart. */
	    at = strrchr(STR(reply.recipient), '@');
	    len = (at ? (at - STR(reply.recipient))
		   : strlen(STR(reply.recipient)));
	    vstring_strncpy(queue_name, STR(reply.recipient), len);
	    /* Remove the address extension from the recipient localpart. */
	    if (*var_rcpt_delim && split_addr(STR(queue_name), var_rcpt_delim))
		vstring_truncate(queue_name, strlen(STR(queue_name)));
	    /* Assume the recipient domain is equivalent to nexthop. */
	    vstring_sprintf_append(queue_name, "@%s", STR(reply.nexthop));
	}
	lowercase(STR(queue_name));

	/*
	 * This transport is alive. Find or instantiate a queue for this
	 * recipient.
	 */
	if (queue == 0 || !STREQ(queue->name, STR(queue_name))) {
	    if ((queue = qmgr_queue_find(transport, STR(queue_name))) == 0)
		queue = qmgr_queue_create(transport, STR(queue_name),
					  STR(reply.nexthop));
	}

	/*
	 * This message is being flushed. If need-be unthrottle the queue.
	 */
	if ((message->qflags & QMGR_FLUSH_EACH) != 0
	    && QMGR_QUEUE_THROTTLED(queue))
	    qmgr_queue_unthrottle(queue);

	/*
	 * This queue is dead. Defer delivery to this recipient.
	 */
	if (QMGR_QUEUE_THROTTLED(queue)) {
	    saved_dsn = queue->dsn;
	    if ((queue = qmgr_error_queue(MAIL_SERVICE_RETRY, saved_dsn)) == 0) {
		qmgr_defer_recipient(message, recipient, saved_dsn);
		continue;
	    }
	}

	/*
	 * This queue is alive. Bind this recipient to this queue instance.
	 */
	recipient->u.queue = queue;
    }
    resolve_clnt_free(&reply);
    vstring_free(queue_name);
}
コード例 #3
0
ファイル: verify_sender_addr.c プロジェクト: ii0/postfix
const char *valid_verify_sender_addr(const char *their_addr)
{
    static VSTRING *time_indep_sender_buf;	/* sender without time stamp */
    ssize_t base_len;
    unsigned long my_epoch;
    unsigned long their_epoch;
    char   *my_at_domain;
    char   *their_at_domain;
    char   *cp;

    /*
     * The null address is always time-independent.
     */
    if (*var_verify_sender == 0 || strcmp(var_verify_sender, "<>") == 0)
	return (*their_addr ? 0 : "");

    /*
     * One-time initialization. Generate the time-independent address that we
     * will return if the match is successful. This address is also used as a
     * matching template.
     */
    if (time_indep_sender_buf == 0) {
	time_indep_sender_buf = vstring_alloc(10);
	vstring_strcpy(time_indep_sender_buf, var_verify_sender);
	rewrite_clnt_internal(MAIL_ATTR_RWR_LOCAL, STR(time_indep_sender_buf),
			      time_indep_sender_buf);
    }

    /*
     * Check the time-independent sender localpart.
     */
    if ((my_at_domain = strchr(STR(time_indep_sender_buf), '@')) != 0)
	base_len = my_at_domain - STR(time_indep_sender_buf);
    else
	base_len = LEN(time_indep_sender_buf);
    if (strncasecmp_utf8(STR(time_indep_sender_buf), their_addr, base_len) != 0)
	return (0);				/* sender localpart mis-match */

    /*
     * Check the time-independent domain.
     */
    if ((their_at_domain = strchr(their_addr, '@')) == 0 && my_at_domain != 0)
	return (0);				/* sender domain mis-match */
    if (their_at_domain != 0
	&& (my_at_domain == 0
	    || strcasecmp_utf8(their_at_domain, my_at_domain) != 0))
	return (0);				/* sender domain mis-match */

    /*
     * Check the time-dependent portion.
     */
    if (var_verify_sender_ttl > 0) {
	their_epoch = safe_strtoul(their_addr + base_len, &cp, VERIFY_BASE);
	if ((*cp != '@' && *cp != 0)
	    || (their_epoch == ULONG_MAX && errno == ERANGE))
	    return (0);				/* malformed time stamp */
	my_epoch = VERIFY_SENDER_ADDR_EPOCH();
	if (their_epoch < my_epoch - 1 || their_epoch > my_epoch + 1)
	    return (0);				/* outside time window */
    }

    /*
     * No time-dependent portion.
     */
    else {
	if (their_addr[base_len] != '@' && their_addr[base_len] != 0)
	    return (0);				/* garbage after sender base */
    }
    return (STR(time_indep_sender_buf));
}
コード例 #4
0
ファイル: verify_sender_addr.c プロジェクト: ii0/postfix
const char *make_verify_sender_addr(void)
{
    static VSTRING *verify_sender_buf;	/* the complete sender address */
    static VSTRING *my_epoch_buf;	/* scratch space */
    char   *my_at_domain;

    /*
     * The null sender is always time-independent.
     */
    if (*var_verify_sender == 0 || strcmp(var_verify_sender, "<>") == 0)
	return ("");

    /*
     * Sanity check.
     */
    if (*var_verify_sender == '@')
	msg_fatal("parameter %s: value \"%s\" must not start with '@'",
		  VAR_VERIFY_SENDER, var_verify_sender);
    if ((my_at_domain = strchr(var_verify_sender, '@')) != 0 && my_at_domain[1] == 0)
	msg_fatal("parameter %s: value \"%s\" must not end with '@'",
		  VAR_VERIFY_SENDER, var_verify_sender);

    /*
     * One-time initialization.
     */
    if (verify_sender_buf == 0) {
	verify_sender_buf = vstring_alloc(10);
	my_epoch_buf = vstring_alloc(10);
    }

    /*
     * Start with the bare sender address.
     */
    vstring_strcpy(verify_sender_buf, var_verify_sender);

    /*
     * Append the time stamp to the address localpart, encoded in some
     * non-decimal form for obscurity.
     * 
     * XXX It would be nice to have safe_ultostr() append-only support.
     */
    if (var_verify_sender_ttl > 0) {
	/* Strip the @domain portion, if applicable. */
	if (my_at_domain != 0)
	    vstring_truncate(verify_sender_buf,
			     (ssize_t) (my_at_domain - var_verify_sender));
	/* Append the time stamp to the address localpart. */
	vstring_sprintf_append(verify_sender_buf, "%s",
			       safe_ultostr(my_epoch_buf,
					    VERIFY_SENDER_ADDR_EPOCH(),
					    VERIFY_BASE, 0, 0));
	/* Add back the @domain, if applicable. */
	if (my_at_domain != 0)
	    vstring_sprintf_append(verify_sender_buf, "%s", my_at_domain);
    }

    /*
     * Rewrite the address to canonical form.
     */
    rewrite_clnt_internal(MAIL_ATTR_RWR_LOCAL, STR(verify_sender_buf),
			  verify_sender_buf);

    return (STR(verify_sender_buf));
}