예제 #1
0
int     smtp_session_passivate(SMTP_SESSION *session, VSTRING *dest_prop,
			               VSTRING *endp_prop)
{
    int     fd;

    /*
     * Encode the local-to-physical binding properties: whether or not this
     * server is best MX host for the next-hop or fall-back logical
     * destination (this information is needed for loop handling in
     * smtp_proto()).
     * 
     * XXX It would be nice to have a VSTRING to VSTREAM adapter so that we can
     * serialize the properties with attr_print() instead of using ad-hoc,
     * non-reusable, code and hard-coded format strings.
     */
    vstring_sprintf(dest_prop, "%u",
		    session->features & SMTP_FEATURE_DESTINATION_MASK);

    /*
     * Encode the physical endpoint properties: all the session properties
     * except for "session from cache", "best MX", or "RSET failure".
     * 
     * XXX It would be nice to have a VSTRING to VSTREAM adapter so that we can
     * serialize the properties with attr_print() instead of using obscure
     * hard-coded format strings.
     * 
     * XXX Should also record an absolute time when a session must be closed,
     * how many non-delivering mail transactions there were during this
     * session, and perhaps other statistics, so that we don't reuse a
     * session too much.
     * 
     * XXX Be sure to use unsigned types in the format string. Sign characters
     * would be rejected by the alldig() test on the reading end.
     */
    vstring_sprintf(endp_prop, "%u\n%s\n%s\n%s\n%u\n%u\n%lu",
		    session->reuse_count,
		    session->dest, session->host,
		    session->addr, session->port,
		    session->features & SMTP_FEATURE_ENDPOINT_MASK,
		    (long) session->expire_time);

    /*
     * Append the passivated SASL attributes.
     */
#ifdef notdef
    if (smtp_sasl_enable)
	smtp_sasl_passivate(endp_prop, session);
#endif

    /*
     * Salvage the underlying file descriptor, and destroy the session
     * object.
     */
    fd = vstream_fileno(session->stream);
    vstream_fdclose(session->stream);
    session->stream = 0;
    smtp_session_free(session);

    return (fd);
}
예제 #2
0
int     recv_pass_attr(int fd, HTABLE **attr, int timeout, ssize_t bufsize)
{
    VSTREAM *fp;
    int     stream_err;

    /*
     * Set up a temporary VSTREAM to receive the attributes.
     * 
     * XXX We use one-character reads to simplify the implementation.
     */
    fp = vstream_fdopen(fd, O_RDWR);
    vstream_control(fp,
		    VSTREAM_CTL_BUFSIZE, bufsize,
		    VSTREAM_CTL_TIMEOUT, timeout,
		    VSTREAM_CTL_START_DEADLINE,
		    VSTREAM_CTL_END);
    (void) attr_scan(fp, ATTR_FLAG_NONE,
		     ATTR_TYPE_HASH, *attr = htable_create(1),
		     ATTR_TYPE_END);
    stream_err = (vstream_feof(fp) || vstream_ferror(fp));
    vstream_fdclose(fp);

    /*
     * Error reporting and recovery.
     */
    if (stream_err) {
	htable_free(*attr, myfree);
	*attr = 0;
	return (-1);
    } else {
	if ((*attr)->used == 0) {
	    htable_free(*attr, myfree);
	    *attr = 0;
	}
	return (0);
    }
}
예제 #3
0
SMTP_SESSION *smtp_session_activate(int fd, VSTRING *dest_prop,
				            VSTRING *endp_prop)
{
    const char *myname = "smtp_session_activate";
    SMTP_SESSION *session;
    char   *dest_props;
    char   *endp_props;
    const char *prop;
    const char *dest;
    const char *host;
    const char *addr;
    unsigned port;
    unsigned features;			/* server features */
    time_t  expire_time;		/* session re-use expiration time */
    unsigned reuse_count;		/* # times reused */

    /*
     * XXX it would be nice to have a VSTRING to VSTREAM adapter so that we
     * can de-serialize the properties with attr_scan(), instead of using
     * ad-hoc, non-reusable code.
     * 
     * XXX As a preliminary solution we use mystrtok(), but that function is not
     * suitable for zero-length fields.
     */
    endp_props = STR(endp_prop);
    if ((prop = mystrtok(&endp_props, "\n")) == 0 || !alldig(prop)) {
	msg_warn("%s: bad cached session reuse count property", myname);
	return (0);
    }
    reuse_count = atoi(prop);
    if ((dest = mystrtok(&endp_props, "\n")) == 0) {
	msg_warn("%s: missing cached session destination property", myname);
	return (0);
    }
    if ((host = mystrtok(&endp_props, "\n")) == 0) {
	msg_warn("%s: missing cached session hostname property", myname);
	return (0);
    }
    if ((addr = mystrtok(&endp_props, "\n")) == 0) {
	msg_warn("%s: missing cached session address property", myname);
	return (0);
    }
    if ((prop = mystrtok(&endp_props, "\n")) == 0 || !alldig(prop)) {
	msg_warn("%s: bad cached session port property", myname);
	return (0);
    }
    port = atoi(prop);

    if ((prop = mystrtok(&endp_props, "\n")) == 0 || !alldig(prop)) {
	msg_warn("%s: bad cached session features property", myname);
	return (0);
    }
    features = atoi(prop);

    if ((prop = mystrtok(&endp_props, "\n")) == 0 || !alldig(prop)) {
	msg_warn("%s: bad cached session expiration time property", myname);
	return (0);
    }
#ifdef MISSING_STRTOUL
    expire_time = strtol(prop, 0, 10);
#else
    expire_time = strtoul(prop, 0, 10);
#endif

    if (dest_prop && VSTRING_LEN(dest_prop)) {
	dest_props = STR(dest_prop);
	if ((prop = mystrtok(&dest_props, "\n")) == 0 || !alldig(prop)) {
	    msg_warn("%s: bad cached destination features property", myname);
	    return (0);
	}
	features |= atoi(prop);
    }

    /*
     * Allright, bundle up what we have sofar.
     */
#define NO_FLAGS	0

    session = smtp_session_alloc(vstream_fdopen(fd, O_RDWR), dest, host,
				 addr, port, (time_t) 0, NO_FLAGS);
    session->features = (features | SMTP_FEATURE_FROM_CACHE);
    CACHE_THIS_SESSION_UNTIL(expire_time);
    session->reuse_count = ++reuse_count;

    if (msg_verbose)
	msg_info("%s: dest=%s host=%s addr=%s port=%u features=0x%x, "
		 "ttl=%ld, reuse=%d",
		 myname, dest, host, addr, ntohs(port), features,
		 (long) (expire_time - time((time_t *) 0)), reuse_count);

    /*
     * Re-activate the SASL attributes.
     */
#ifdef notdef
    if (smtp_sasl_enable && smtp_sasl_activate(session, endp_props) < 0) {
	vstream_fdclose(session->stream);
	session->stream = 0;
	smtp_session_free(session);
	return (0);
    }
#endif

    return (session);
}
예제 #4
0
파일: smtp_session.c 프로젝트: tmtm/postfix
int     smtp_session_passivate(SMTP_SESSION *session, VSTRING *dest_prop,
			               VSTRING *endp_prop)
{
    SMTP_ITERATOR *iter = session->iterator;
    VSTREAM *mp;
    int     fd;

    /*
     * Encode the delivery request next-hop to endpoint binding properties:
     * whether or not this server is best MX host for the delivery request
     * next-hop or fall-back logical destination (this information is needed
     * for loop handling in smtp_proto()).
     * 
     * TODO: save SASL username and password information so that we can
     * correctly save a reused authenticated connection.
     * 
     * These memory writes should never fail.
     */
    if ((mp = vstream_memopen(dest_prop, O_WRONLY)) == 0
	|| attr_print_plain(mp, ATTR_FLAG_NONE,
			    SEND_ATTR_STR(SESS_ATTR_DEST, STR(iter->dest)),
			    SEND_ATTR_STR(SESS_ATTR_HOST, STR(iter->host)),
			    SEND_ATTR_STR(SESS_ATTR_ADDR, STR(iter->addr)),
			    SEND_ATTR_INT(SESS_ATTR_DEST_FEATURES,
			 session->features & SMTP_FEATURE_DESTINATION_MASK),
			    ATTR_TYPE_END) != 0
	|| vstream_fclose(mp) != 0)
	msg_fatal("smtp_session_passivate: can't save dest properties: %m");

    /*
     * Encode the physical endpoint properties: all the session properties
     * except for "session from cache", "best MX", or "RSET failure". Plus
     * the TLS level, reuse count, and connection expiration time.
     * 
     * XXX Should also record how many non-delivering mail transactions there
     * were during this session, and perhaps other statistics, so that we
     * don't reuse a session too much.
     * 
     * TODO: passivate SASL username and password information so that we can
     * correctly save a reused authenticated connection.
     * 
     * These memory writes should never fail.
     */
    if ((mp = vstream_memopen(endp_prop, O_WRONLY)) == 0
	|| attr_print_plain(mp, ATTR_FLAG_NONE,
#ifdef USE_TLS
			    SEND_ATTR_INT(SESS_ATTR_TLS_LEVEL,
					  session->state->tls->level),
#endif
			    SEND_ATTR_INT(SESS_ATTR_REUSE_COUNT,
					  session->reuse_count),
			    SEND_ATTR_INT(SESS_ATTR_ENDP_FEATURES,
			    session->features & SMTP_FEATURE_ENDPOINT_MASK),
			    SEND_ATTR_LONG(SESS_ATTR_EXPIRE_TIME,
					   (long) session->expire_time),
			    ATTR_TYPE_END) != 0

    /*
     * Append the passivated TLS context. These memory writes should never
     * fail.
     */
#ifdef USE_TLS
	|| (session->tls_context
	    && attr_print_plain(mp, ATTR_FLAG_NONE,
				SEND_ATTR_FUNC(tls_proxy_context_print,
					     (void *) session->tls_context),
				ATTR_TYPE_END) != 0)
#endif
	|| vstream_fclose(mp) != 0)
	msg_fatal("smtp_session_passivate: cannot save TLS context: %m");

    /*
     * Salvage the underlying file descriptor, and destroy the session
     * object.
     */
    fd = vstream_fileno(session->stream);
    vstream_fdclose(session->stream);
    session->stream = 0;
    smtp_session_free(session);

    return (fd);
}
예제 #5
0
void    psc_send_socket(PSC_STATE *state)
{
    const char *myname = "psc_send_socket";
    int     server_fd;
    int     pass_err;
    VSTREAM *fp;

    if (msg_verbose > 1)
	msg_info("%s: sq=%d cq=%d send socket %d from [%s]:%s",
		 myname, psc_post_queue_length, psc_check_queue_length,
		 vstream_fileno(state->smtp_client_stream),
		 state->smtp_client_addr, state->smtp_client_port);

    /*
     * Connect to the real SMTP service over a local IPC channel, send the
     * file descriptor, and close the file descriptor to save resources.
     * Experience has shown that some systems will discard information when
     * we close a channel immediately after writing. Thus, we waste resources
     * waiting for the remote side to close the local IPC channel first. The
     * good side of waiting is that we learn when the real SMTP server is
     * falling behind.
     * 
     * This is where we would forward the connection to an SMTP server that
     * provides an appropriate level of service for this client class. For
     * example, a server that is more forgiving, or one that is more
     * suspicious. Alternatively, we could send attributes along with the
     * socket with client reputation information, making everything even more
     * Postfix-specific.
     */
    if ((server_fd =
	 LOCAL_CONNECT(psc_smtpd_service_name, NON_BLOCKING,
		       PSC_SEND_SOCK_CONNECT_TIMEOUT)) < 0) {
	msg_warn("cannot connect to service %s: %m", psc_smtpd_service_name);
	if (state->flags & PSC_STATE_FLAG_PREGR_TODO) {
	    PSC_SMTPD_X21(state, "421 4.3.2 No system resources\r\n");
	} else {
	    PSC_SEND_REPLY(state, "421 4.3.2 All server ports are busy\r\n");
	    psc_free_session_state(state);
	}
	return;
    }
    /* XXX Note: no dummy read between LOCAL_SEND_FD() and attr_print(). */
    fp = vstream_fdopen(server_fd, O_RDWR);
    pass_err =
	(LOCAL_SEND_FD(server_fd,
		       vstream_fileno(state->smtp_client_stream)) < 0
	 || (attr_print(fp, ATTR_FLAG_NONE,
	  SEND_ATTR_STR(MAIL_ATTR_ACT_CLIENT_ADDR, state->smtp_client_addr),
	  SEND_ATTR_STR(MAIL_ATTR_ACT_CLIENT_PORT, state->smtp_client_port),
	  SEND_ATTR_STR(MAIL_ATTR_ACT_SERVER_ADDR, state->smtp_server_addr),
	  SEND_ATTR_STR(MAIL_ATTR_ACT_SERVER_PORT, state->smtp_server_port),
			ATTR_TYPE_END) || vstream_fflush(fp)));
    /* XXX Note: no read between attr_print() and vstream_fdclose(). */
    (void) vstream_fdclose(fp);
    if (pass_err != 0) {
	msg_warn("cannot pass connection to service %s: %m",
		 psc_smtpd_service_name);
	(void) close(server_fd);
	if (state->flags & PSC_STATE_FLAG_PREGR_TODO) {
	    PSC_SMTPD_X21(state, "421 4.3.2 No system resources\r\n");
	} else {
	    PSC_SEND_REPLY(state, "421 4.3.2 No system resources\r\n");
	    psc_free_session_state(state);
	}
	return;
    } else {

	/*
	 * Closing the smtp_client_fd here triggers a FreeBSD 7.1 kernel bug
	 * where smtp-source sometimes sees the connection being closed after
	 * it has already received the real SMTP server's 220 greeting!
	 */
#if 0
	PSC_DEL_CLIENT_STATE(state);
#endif
	PSC_ADD_SERVER_STATE(state, server_fd);
	PSC_READ_EVENT_REQUEST(state->smtp_server_fd, psc_send_socket_close_event,
			       (void *) state, PSC_SEND_SOCK_NOTIFY_TIMEOUT);
	return;
    }
}