Exemplo n.º 1
0
void    psc_conclude(PSC_STATE *state)
{
    const char *myname = "psc_conclude";

    if (msg_verbose)
	msg_info("flags for %s: %s",
		 myname, psc_print_state_flags(state->flags, myname));

    /*
     * Handle clients that passed at least one test other than permanent
     * whitelisting, and that didn't fail any test including permanent
     * blacklisting. There may still be unfinished tests; those tests will
     * need to be completed when the client returns in a later session.
     */
    if (state->flags & PSC_STATE_MASK_ANY_FAIL)
	state->flags &= ~PSC_STATE_MASK_ANY_PASS;

    /*
     * Log our final blessing when all unfinished tests were completed.
     */
    if ((state->flags & PSC_STATE_MASK_ANY_PASS) != 0
	&& (state->flags & PSC_STATE_MASK_ANY_PASS) ==
	PSC_STATE_FLAGS_TODO_TO_PASS(state->flags & PSC_STATE_MASK_ANY_TODO))
	msg_info("PASS %s [%s]:%s", (state->flags & PSC_STATE_FLAG_NEW) == 0
		 || state->client_info->pass_new_count++ > 0 ?
		 "OLD" : "NEW", PSC_CLIENT_ADDR_PORT(state));

    /*
     * Update the postscreen cache. This still supports a scenario where a
     * client gets whitelisted in the course of multiple sessions, as long as
     * that client does not "fail" any test. Don't try to optimize away cache
     * updates; we want cached information to be up-to-date even if a test
     * result is renewed during overlapping SMTP sessions, and even if
     * 'postfix reload' happens in the middle of that.
     */
    if ((state->flags & PSC_STATE_MASK_ANY_UPDATE) != 0
	&& psc_cache_map != 0) {
	psc_print_tests(psc_temp, state);
	psc_cache_update(psc_cache_map, state->smtp_client_addr, STR(psc_temp));
    }

    /*
     * Either hand off the socket to a real SMTP engine, or say bye-bye.
     */
    if ((state->flags & PSC_STATE_FLAG_NOFORWARD) == 0) {
	psc_send_socket(state);
    } else {
	if ((state->flags & PSC_STATE_FLAG_HANGUP) == 0)
	    (void) PSC_SEND_REPLY(state, state->final_reply);
	msg_info("DISCONNECT [%s]:%s", PSC_CLIENT_ADDR_PORT(state));
	psc_free_session_state(state);
    }
}
Exemplo n.º 2
0
static void psc_send_socket_close_event(int event, char *context)
{
    const char *myname = "psc_send_socket_close_event";
    PSC_STATE *state = (PSC_STATE *) context;

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

    /*
     * The real SMTP server has closed the local IPC channel, or we have
     * reached the limit of our patience. In the latter case it is still
     * possible that the real SMTP server will receive the socket so we
     * should not interfere.
     */
    PSC_CLEAR_EVENT_REQUEST(state->smtp_server_fd, psc_send_socket_close_event,
			    context);
    if (event == EVENT_TIME)
	msg_warn("timeout sending connection to service %s",
		 psc_smtpd_service_name);
    psc_free_session_state(state);
}
Exemplo n.º 3
0
void    psc_send_socket(PSC_STATE *state)
{
    const char *myname = "psc_send_socket";
    int     server_fd;

    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 =
	 PASS_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;
    }
    if (LOCAL_SEND_FD(server_fd,
		      vstream_fileno(state->smtp_client_stream)) < 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,
			       (char *) state, PSC_SEND_SOCK_NOTIFY_TIMEOUT);
	return;
    }
}