예제 #1
0
static SMTP_SESSION *smtp_connect_sock(int sock, struct sockaddr *sa,
				               int salen,
				               SMTP_ITERATOR *iter,
				               DSN_BUF *why,
				               int sess_flags)
{
    int     conn_stat;
    int     saved_errno;
    VSTREAM *stream;
    time_t  start_time;
    const char *name = STR(iter->host);
    const char *addr = STR(iter->addr);
    unsigned port = iter->port;

    start_time = time((time_t *) 0);
    if (var_smtp_conn_tmout > 0) {
	non_blocking(sock, NON_BLOCKING);
	conn_stat = timed_connect(sock, sa, salen, var_smtp_conn_tmout);
	saved_errno = errno;
	non_blocking(sock, BLOCKING);
	errno = saved_errno;
    } else {
	conn_stat = sane_connect(sock, sa, salen);
    }
    if (conn_stat < 0) {
	if (port)
	    dsb_simple(why, "4.4.1", "connect to %s[%s]:%d: %m",
		       name, addr, ntohs(port));
	else
	    dsb_simple(why, "4.4.1", "connect to %s[%s]: %m", name, addr);
	close(sock);
	return (0);
    }
    stream = vstream_fdopen(sock, O_RDWR);

    /*
     * Avoid poor performance when TCP MSS > VSTREAM_BUFSIZE.
     */
    if (sa->sa_family == AF_INET
#ifdef AF_INET6
	|| sa->sa_family == AF_INET6
#endif
	)
	vstream_tweak_tcp(stream);

    /*
     * Bundle up what we have into a nice SMTP_SESSION object.
     */
    return (smtp_session_alloc(stream, iter, start_time, sess_flags));
}
예제 #2
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);
}
예제 #3
0
파일: smtp_session.c 프로젝트: tmtm/postfix
SMTP_SESSION *smtp_session_activate(int fd, SMTP_ITERATOR *iter,
				            VSTRING *dest_prop,
				            VSTRING *endp_prop)
{
    const char *myname = "smtp_session_activate";
    VSTREAM *mp;
    SMTP_SESSION *session;
    int     endp_features;		/* server features */
    int     dest_features;		/* server features */
    long    expire_time;		/* session re-use expiration time */
    int     reuse_count;		/* # times reused */

#ifdef USE_TLS
    TLS_SESS_STATE *tls_context = 0;
    SMTP_TLS_POLICY *tls = iter->parent->tls;

#define TLS_PROXY_CONTEXT_FREE() do { \
    if (tls_context) \
	tls_proxy_context_free(tls_context); \
   } while (0)
#else
#define TLS_PROXY_CONTEXT_FREE()		/* nothing */
#endif

#define SMTP_SESSION_ACTIVATE_ERR_RETURN() do { \
	TLS_PROXY_CONTEXT_FREE(); \
	return (0); \
   } while (0)

    /*
     * Sanity check: if TLS is required, the cached properties must contain a
     * TLS context.
     */
    if ((mp = vstream_memopen(endp_prop, O_RDONLY)) == 0
	|| attr_scan_plain(mp, ATTR_FLAG_NONE,
#ifdef USE_TLS
			   RECV_ATTR_INT(SESS_ATTR_TLS_LEVEL,
					 &tls->level),
#endif
			   RECV_ATTR_INT(SESS_ATTR_REUSE_COUNT,
					 &reuse_count),
			   RECV_ATTR_INT(SESS_ATTR_ENDP_FEATURES,
					 &endp_features),
			   RECV_ATTR_LONG(SESS_ATTR_EXPIRE_TIME,
					  &expire_time),
			   ATTR_TYPE_END) != 4
#ifdef USE_TLS
	|| ((tls->level > TLS_LEV_MAY
	     || (tls->level == TLS_LEV_MAY && vstream_peek(mp) > 0))
	    && attr_scan_plain(mp, ATTR_FLAG_NONE,
			       RECV_ATTR_FUNC(tls_proxy_context_scan,
					      (void *) &tls_context),
			       ATTR_TYPE_END) != 1)
#endif
	|| vstream_fclose(mp) != 0) {
	msg_warn("smtp_session_activate: bad cached endp properties");
	SMTP_SESSION_ACTIVATE_ERR_RETURN();
    }

    /*
     * Clobber the iterator's current nexthop, host and address fields with
     * cached-connection information. This is done when a session is looked
     * up by delivery request nexthop instead of address and port. It is the
     * caller's responsibility to save and restore the delivery request
     * nexthop with SMTP_ITER_SAVE_DEST() and SMTP_ITER_RESTORE_DEST().
     * 
     * TODO: Eliminate the duplication between SMTP_ITERATOR and SMTP_SESSION.
     * 
     * TODO: restore SASL username and password information so that we can
     * correctly save a reused authenticated connection.
     */
    if (dest_prop && VSTRING_LEN(dest_prop)) {
	if ((mp = vstream_memopen(dest_prop, O_RDONLY)) == 0
	    || attr_scan_plain(mp, ATTR_FLAG_NONE,
			       RECV_ATTR_STR(SESS_ATTR_DEST, iter->dest),
			       RECV_ATTR_STR(SESS_ATTR_HOST, iter->host),
			       RECV_ATTR_STR(SESS_ATTR_ADDR, iter->addr),
			       RECV_ATTR_INT(SESS_ATTR_DEST_FEATURES,
					     &dest_features),
			       ATTR_TYPE_END) != 4
	    || vstream_fclose(mp) != 0) {
	    msg_warn("smtp_session_passivate: bad cached dest properties");
	    SMTP_SESSION_ACTIVATE_ERR_RETURN();
	}
    } else {
	dest_features = 0;
    }
#ifdef USE_TLS
    if (msg_verbose)
	msg_info("%s: tls_level=%d", myname, tls->level);
#endif

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

    session = smtp_session_alloc(vstream_fdopen(fd, O_RDWR), iter,
				 (time_t) 0, NO_FLAGS);
    session->features =
	(endp_features | dest_features | SMTP_FEATURE_FROM_CACHE);
#ifdef USE_TLS
    session->tls_context = tls_context;
#endif
    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, STR(iter->dest), STR(iter->host),
		 STR(iter->addr), ntohs(iter->port),
		 endp_features | dest_features,
		 (long) (expire_time - time((time_t *) 0)),
		 reuse_count);

#if USE_TLS
    if (tls_context)
	tls_log_summary(TLS_ROLE_CLIENT, TLS_USAGE_USED,
			session->tls_context);
#endif

    return (session);
}