Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Postfix/src/postscreen/   (Postfix Mailserver Version 3.11©)  Datei vom 27.7.2018 mit Größe 9 kB image not shown  

Impressum postscreen_send.c

  Sprache: C
 

/*++
/* NAME
/* postscreen_send 3
/* SUMMARY
/* postscreen low-level output
/* SYNOPSIS
/* #include <postscreen.h>
/*
/* void pcs_send_pre_jail_init(void)
/*
/* int psc_send_reply(state, text)
/* PSC_STATE *state;
/* const char *text;
/*
/* int PSC_SEND_REPLY(state, text)
/* PSC_STATE *state;
/* const char *text;
/*
/* void psc_send_socket(state)
/* PSC_STATE *state;
/* DESCRIPTION
/* pcs_send_pre_jail_init() performs one-time initialization.
/*
/* psc_send_reply() sends the specified text to the specified
/* remote SMTP client.  In case of an immediate error, it logs
/* a warning (except EPIPE) with the client address and port,
/* and returns a non-zero result (all errors including EPIPE).
/*
/* psc_send_reply() does a best effort to send the reply, but
/* it won't block when the output is throttled by a hostile
/* peer.
/*
/* PSC_SEND_REPLY() is a legacy wrapper for psc_send_reply().
/* It will eventually be replaced by its expansion.
/*
/* psc_send_socket() sends the specified socket to the real
/* Postfix SMTP server. The socket is delivered in the background.
/* This function must be called after all other session-related
/* work is finished including postscreen cache updates.
/*
/* In case of an immediate error, psc_send_socket() sends a 421
/* reply to the remote SMTP client and closes the connection.
/* If the 220- greeting was sent, sending 421 would be invalid;
/* instead, the client is redirected to the dummy SMTP engine
/* which sends the 421 reply at the first legitimate opportunity.
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*
/* Wietse Venema
/* Google, Inc.
/* 111 8th Avenue
/* New York, NY 10011, USA
/*--*/


/* System library. */

#include <sys_defs.h>
#include <string.h>
#include <errno.h>

/* Utility library. */

#include <msg.h>
#include <iostuff.h>
#include <connect.h>
#include <attr.h>
#include <vstream.h>

/* Global library. */

#include <mail_params.h>
#include <smtp_reply_footer.h>
#include <mail_proto.h>
#include <maps.h>

/* Application-specific. */

#include <postscreen.h>

static MAPS *psc_rej_ftr_maps;

 /*
  * This program screens all inbound SMTP connections, so it better not waste
  * time.
  */

#define PSC_SEND_SOCK_CONNECT_TIMEOUT 1
#define PSC_SEND_SOCK_NOTIFY_TIMEOUT 100

/* pcs_send_pre_jail_init - initialize */

void    pcs_send_pre_jail_init(void)
{
    static int init_count = 0;

    if (init_count++ != 0)
 msg_panic("pcs_send_pre_jail_init: multiple calls");

    /*
     * SMTP server reject footer.
     */

    if (*var_psc_rej_ftr_maps)
 psc_rej_ftr_maps = maps_create(VAR_SMTPD_REJ_FTR_MAPS,
           var_psc_rej_ftr_maps,
           DICT_FLAG_LOCK);
}

/* psc_get_footer - find that footer */

static const char *psc_get_footer(const char *text, ssize_t text_len)
{
    static VSTRING *footer_buf = 0;

    if (footer_buf == 0)
 footer_buf = vstring_alloc(100);
    /* Strip the \r\n for consistency with smtpd. */
    vstring_strncpy(footer_buf, text, text_len);
    return (psc_maps_find(psc_rej_ftr_maps, STR(footer_buf), 0));
}

/* psc_send_reply - send reply to remote SMTP client */

int     psc_send_reply(PSC_STATE *state, const char *text)
{
    ssize_t start;
    int     ret;
    const char *footer;
    ssize_t text_len = strlen(text) - 2;

    if (msg_verbose)
 msg_info("> [%s]:%s: %.*s", state->smtp_client_addr,
   state->smtp_client_port, (int) text_len, text);

    /*
     * Append the new text to earlier text that could not be sent because the
     * output was throttled.
     */

    start = VSTRING_LEN(state->send_buf);
    vstring_strcat(state->send_buf, text);

    /*
     * For soft_bounce support, we also fix the REJECT logging before the
     * dummy SMTP engine calls the psc_send_reply() output routine. We do
     * some double work, but it is for debugging only.
     */

    if (var_soft_bounce) {
 if (text[0] == '5')
     STR(state->send_buf)[start + 0] = '4';
 if (text[4] == '5')
     STR(state->send_buf)[start + 4] = '4';
    }

    /*
     * Append the optional reply footer.
     */

    if ((*text == '4' || *text == '5')
 && ((psc_rej_ftr_maps != 0
      && (footer = psc_get_footer(text, text_len)) != 0)
     || *(footer = var_psc_rej_footer) != 0))
 smtp_reply_footer(state->send_buf, start, footer,
     STR(psc_expand_filter), psc_expand_lookup,
     (void *) state);

    /*
     * Do a best effort sending text, but don't block when the output is
     * throttled by a hostile peer.
     */

    ret = write(vstream_fileno(state->smtp_client_stream),
  STR(state->send_buf), LEN(state->send_buf));
    if (ret > 0)
 vstring_truncate(state->send_buf, ret - LEN(state->send_buf));
    if (ret < 0 && errno != EAGAIN && errno != EPIPE && errno != ECONNRESET)
 msg_warn("write [%s]:%s: %m", state->smtp_client_addr,
   state->smtp_client_port);
    return (ret < 0 && errno != EAGAIN);
}

/* psc_send_socket_close_event - file descriptor has arrived or timeout */

static void psc_send_socket_close_event(int event, void *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);
}

/* psc_send_socket - send socket to real SMTP server process */

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;
    }
}

Messung V0.5 in Prozent
C=96 H=100 G=97

¤ Dauer der Verarbeitung: 0.23 Sekunden  (vorverarbeitet am  2026-08-08) ¤

*Bot Zugriff






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.