Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  postscreen_early.c

  Sprache: C
 

/*++
/* NAME
/* postscreen_early 3
/* SUMMARY
/* postscreen pre-handshake tests
/* SYNOPSIS
/* #include <postscreen.h>
/*
/* void psc_early_init(void)
/*
/* void psc_early_tests(state)
/* PSC_STATE *state;
/* DESCRIPTION
/* psc_early_tests() performs protocol tests before the SMTP
/* handshake: the pregreet test and the DNSBL test. Control
/* is passed to the psc_smtpd_tests() routine as appropriate.
/*
/* psc_early_init() performs one-time initialization.
/* 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 <sys/socket.h>
#include <limits.h>

/* Utility library. */

#include <msg.h>
#include <stringops.h>
#include <mymalloc.h>
#include <vstring.h>

/* Global library. */

#include <mail_params.h>

/* Application-specific. */

#include <postscreen.h>

static char *psc_teaser_greeting;
static VSTRING *psc_escape_buf;

/* psc_allowlist_non_dnsbl - allowlist pending non-dnsbl tests */

static void psc_allowlist_non_dnsbl(PSC_STATE *state)
{
    time_t  now;
    int     tindx;

    /*
     * If no tests failed (we can't undo those), and if the allowlist
     * threshold is met, flag non-dnsbl tests that are pending or disabled as
     * successfully completed, and set their expiration times equal to the
     * DNSBL expiration time, except for tests that would expire later.
     * 
     * Why flag disabled tests as passed? When a disabled test is turned on,
     * postscreen should not apply that test to clients that are already
     * allowlisted based on their combined DNSBL score.
     */

    if ((state->flags & PSC_STATE_MASK_ANY_FAIL) == 0
 && state->dnsbl_score < var_psc_dnsbl_thresh
 && var_psc_dnsbl_althresh < 0
 && state->dnsbl_score <= var_psc_dnsbl_althresh) {
 now = event_time();
 for (tindx = 0; tindx < PSC_TINDX_COUNT; tindx++) {
     if (tindx == PSC_TINDX_DNSBL)
  continue;
     if ((state->flags & PSC_STATE_FLAG_BYTINDX_TODO(tindx))
  && !(state->flags & PSC_STATE_FLAG_BYTINDX_PASS(tindx))) {
  if (msg_verbose)
      msg_info("skip %s test for [%s]:%s",
    psc_test_name(tindx), PSC_CLIENT_ADDR_PORT(state));
  /* Wrong for deep protocol tests, but we disable those. */
  state->flags |= PSC_STATE_FLAG_BYTINDX_DONE(tindx);
  /* This also disables pending deep protocol tests. */
  state->flags |= PSC_STATE_FLAG_BYTINDX_PASS(tindx);
     }
     /* Update expiration even if the test was completed or disabled. */
     if (state->client_info->expire_time[tindx] < now + state->dnsbl_ttl)
  state->client_info->expire_time[tindx] = now + state->dnsbl_ttl;
 }
    }
}

/* psc_early_event - handle pre-greet, EOF, and DNSBL results. */

static void psc_early_event(int event, void *context)
{
    const char *myname = "psc_early_event";
    PSC_STATE *state = (PSC_STATE *) context;
    time_t *expire_time = state->client_info->expire_time;
    char    read_buf[PSC_READ_BUF_SIZE];
    int     read_count;
    DELTA_TIME elapsed;

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

    PSC_CLEAR_EVENT_REQUEST(vstream_fileno(state->smtp_client_stream),
       psc_early_event, context);

    /*
     * XXX Be sure to empty the DNSBL lookup buffer otherwise we have a
     * memory leak.
     * 
     * XXX We can avoid "forgetting" to do this by keeping a pointer to the
     * DNSBL lookup buffer in the PSC_STATE structure. This also allows us to
     * shave off a hash table lookup when retrieving the DNSBL result.
     * 
     * A direct pointer increases the odds of dangling pointers. Hash-table
     * lookup is safer, and that is why it's done that way.
     */

    switch (event) {

 /*
  * We either reached the end of the early tests time limit, or all
  * early tests completed before the pregreet timer would go off.
 */

    case EVENT_TIME:

 /*
  * Check if the SMTP client spoke before its turn.
 */

 if ((state->flags & PSC_STATE_FLAG_PREGR_TODO) != 0
     && (state->flags & PSC_STATE_MASK_PREGR_FAIL_DONE) == 0) {
     expire_time[PSC_TINDX_PREGR] = event_time() + var_psc_pregr_ttl;
     PSC_PASS_SESSION_STATE(state, "pregreet test",
       PSC_STATE_FLAG_PREGR_PASS);
 }
 if ((state->flags & PSC_STATE_FLAG_PREGR_FAIL)
     && psc_pregr_action == PSC_ACT_IGNORE) {
     PSC_UNFAIL_SESSION_STATE(state, PSC_STATE_FLAG_PREGR_FAIL);
     /* Not: PSC_PASS_SESSION_STATE. Repeat this test the next time. */
 }

 /*
  * Collect the DNSBL score, and allowlist other tests if applicable.
  * Note: this score will be partial when some DNS lookup did not
  * complete before the pregreet timer expired.
  * 
  * If the client is DNS blocklisted, drop the connection, send the
  * client to a dummy protocol engine, or continue to the next test.
 */

#define PSC_DNSBL_FORMAT \
 "%s 5.7.1 Service unavailable; client [%s] blocked using %s\r\n"
#define NO_DNSBL_SCORE INT_MAX

 if (state->flags & PSC_STATE_FLAG_DNSBL_TODO) {
     if (state->dnsbl_score == NO_DNSBL_SCORE) {
  state->dnsbl_score =
      psc_dnsbl_retrieve(state->smtp_client_addr,
           &state->dnsbl_name,
           state->dnsbl_index,
           &state->dnsbl_ttl);
  if (var_psc_dnsbl_althresh < 0)
      psc_allowlist_non_dnsbl(state);
     }
     if (state->dnsbl_score < var_psc_dnsbl_thresh) {
  expire_time[PSC_TINDX_DNSBL] = event_time() + state->dnsbl_ttl;
  PSC_PASS_SESSION_STATE(state, "dnsbl test",
           PSC_STATE_FLAG_DNSBL_PASS);
     } else {
  msg_info("DNSBL rank %d for [%s]:%s",
    state->dnsbl_score, PSC_CLIENT_ADDR_PORT(state));
  PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_DNSBL_FAIL);
  switch (psc_dnsbl_action) {
  case PSC_ACT_DROP:
      state->dnsbl_reply = vstring_sprintf(vstring_alloc(100),
          PSC_DNSBL_FORMAT, "521",
          state->smtp_client_addr,
        state->dnsbl_name);
      PSC_DROP_SESSION_STATE(state, STR(state->dnsbl_reply));
      return;
  case PSC_ACT_ENFORCE:
      state->dnsbl_reply = vstring_sprintf(vstring_alloc(100),
          PSC_DNSBL_FORMAT, "550",
          state->smtp_client_addr,
        state->dnsbl_name);
      PSC_ENFORCE_SESSION_STATE(state, STR(state->dnsbl_reply));
      break;
  case PSC_ACT_IGNORE:
      PSC_UNFAIL_SESSION_STATE(state, PSC_STATE_FLAG_DNSBL_FAIL);
      /* Not: PSC_PASS_SESSION_STATE. Repeat this test. */
      break;
  default:
      msg_panic("%s: unknown dnsbl action value %d",
         myname, psc_dnsbl_action);

  }
     }
 }

 /*
  * Pass the connection to a real SMTP server, or enter the dummy
  * engine for deep tests.
 */

 if ((state->flags & PSC_STATE_FLAG_NOFORWARD) != 0
     || ((state->flags & PSC_STATE_MASK_SMTPD_PASS)
  != PSC_STATE_FLAGS_TODO_TO_PASS(state->flags & PSC_STATE_MASK_SMTPD_TODO)))
     psc_smtpd_tests(state);
 else
     psc_conclude(state);
 return;

 /*
  * EOF, or the client spoke before its turn. We simply drop the
  * connection, or we continue waiting and allow DNS replies to
  * trickle in.
 */

    default:
 if ((read_count = recv(vstream_fileno(state->smtp_client_stream),
     read_buf, sizeof(read_buf) - 1, MSG_PEEK)) <= 0) {
     /* Avoid memory leak. */
     if (state->dnsbl_score == NO_DNSBL_SCORE
  && (state->flags & PSC_STATE_FLAG_DNSBL_TODO))
  (void) psc_dnsbl_retrieve(state->smtp_client_addr,
       &state->dnsbl_name,
       state->dnsbl_index,
       &state->dnsbl_ttl);
     /* XXX Wait for DNS replies to come in. */
     psc_hangup_event(state);
     return;
 }
 read_buf[read_count] = 0;
 escape(psc_escape_buf, read_buf, read_count);
 msg_info("PREGREET %d after %s from [%s]:%s: %.100s", read_count,
        psc_format_delta_time(psc_temp, state->start_time, &elapsed),
   PSC_CLIENT_ADDR_PORT(state), STR(psc_escape_buf));
 PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_PREGR_FAIL);
 switch (psc_pregr_action) {
 case PSC_ACT_DROP:
     /* Avoid memory leak. */
     if (state->dnsbl_score == NO_DNSBL_SCORE
  && (state->flags & PSC_STATE_FLAG_DNSBL_TODO))
  (void) psc_dnsbl_retrieve(state->smtp_client_addr,
       &state->dnsbl_name,
       state->dnsbl_index,
       &state->dnsbl_ttl);
     PSC_DROP_SESSION_STATE(state, "521 5.5.1 Protocol error\r\n");
     return;
 case PSC_ACT_ENFORCE:
     /* We call psc_dnsbl_retrieve() when the timer expires. */
     PSC_ENFORCE_SESSION_STATE(state, "550 5.5.1 Protocol error\r\n");
     break;
 case PSC_ACT_IGNORE:
     /* We call psc_dnsbl_retrieve() when the timer expires. */
     /* We must handle this case after the timer expires. */
     break;
 default:
     msg_panic("%s: unknown pregreet action value %d",
        myname, psc_pregr_action);
 }

 /*
  * Terminate the greet delay if we're just waiting for the pregreet
  * test to complete. It is safe to call psc_early_event directly,
  * since we are already in that function.
  * 
  * XXX After this code passes all tests, swap around the two blocks in
  * this switch statement and fall through from EVENT_READ into
  * EVENT_TIME, instead of calling psc_early_event recursively.
 */

 state->flags |= PSC_STATE_FLAG_PREGR_DONE;
 if (elapsed.dt_sec >= PSC_EFF_GREET_WAIT
     || ((state->flags & PSC_STATE_MASK_EARLY_DONE)
  == PSC_STATE_FLAGS_TODO_TO_DONE(state->flags & PSC_STATE_MASK_EARLY_TODO)))
     psc_early_event(EVENT_TIME, context);
 else
     event_request_timer(psc_early_event, context,
    PSC_EFF_GREET_WAIT - elapsed.dt_sec);
 return;
    }
}

/* psc_early_dnsbl_event - cancel pregreet timer if waiting for DNS only */

static void psc_early_dnsbl_event(int unused_event, void *context)
{
    const char *myname = "psc_early_dnsbl_event";
    PSC_STATE *state = (PSC_STATE *) context;

    if (msg_verbose)
 msg_info("%s: notify [%s]:%s", myname, PSC_CLIENT_ADDR_PORT(state));

    /*
     * Collect the DNSBL score, and allowlist other tests if applicable.
     */

    state->dnsbl_score =
 psc_dnsbl_retrieve(state->smtp_client_addr, &state->dnsbl_name,
      state->dnsbl_index, &state->dnsbl_ttl);
    if (var_psc_dnsbl_althresh < 0)
 psc_allowlist_non_dnsbl(state);

    /*
     * Terminate the greet delay if we're just waiting for DNSBL lookup to
     * complete. Don't call psc_early_event directly, that would result in a
     * dangling pointer.
     */

    state->flags |= PSC_STATE_FLAG_DNSBL_DONE;
    if ((state->flags & PSC_STATE_MASK_EARLY_DONE)
 == PSC_STATE_FLAGS_TODO_TO_DONE(state->flags & PSC_STATE_MASK_EARLY_TODO))
 event_request_timer(psc_early_event, context, EVENT_NULL_DELAY);
}

/* psc_early_tests - start the early (before protocol) tests */

void    psc_early_tests(PSC_STATE *state)
{
    const char *myname = "psc_early_tests";

    /*
     * Report errors and progress in the context of this test.
     */

    PSC_BEGIN_TESTS(state, "tests before SMTP handshake");

    /*
     * Run a PREGREET test. Send half the greeting banner, by way of teaser,
     * then wait briefly to see if the client speaks before its turn.
     */

    if ((state->flags & PSC_STATE_FLAG_PREGR_TODO) != 0
 && psc_teaser_greeting != 0
 && PSC_SEND_REPLY(state, psc_teaser_greeting) != 0) {
 psc_hangup_event(state);
 return;
    }

    /*
     * Run a DNS blocklist query.
     */

    if ((state->flags & PSC_STATE_FLAG_DNSBL_TODO) != 0)
 state->dnsbl_index =
     psc_dnsbl_request(state->smtp_client_addr, psc_early_dnsbl_event,
         (void *) state);
    else
 state->dnsbl_index = -1;
    state->dnsbl_score = NO_DNSBL_SCORE;

    /*
     * Wait for the client to respond or for DNS lookup to complete.
     */

    if ((state->flags & PSC_STATE_FLAG_PREGR_TODO) != 0)
 PSC_READ_EVENT_REQUEST(vstream_fileno(state->smtp_client_stream),
         psc_early_event, (void *) state, PSC_EFF_GREET_WAIT);
    else
 event_request_timer(psc_early_event, (void *) state, PSC_EFF_GREET_WAIT);
}

/* psc_early_init - initialize early tests */

void    psc_early_init(void)
{
    if (*var_psc_pregr_banner) {
 vstring_sprintf(psc_temp, "220-%s\r\n", var_psc_pregr_banner);
 psc_teaser_greeting = mystrdup(STR(psc_temp));
 psc_escape_buf = vstring_alloc(100);
    }
}

Messung V0.5 in Prozent
C=86 H=98 G=91

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

*© Formatika GbR, Deutschland






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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=141584
#Domains=738142