Eine aufbereitete Darstellung der Quelle

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

Benutzer

Quelle  milter.c

  Sprache: C
 

/*++
/* NAME
/* milter 3
/* SUMMARY
/* generic MTA-side mail filter interface
/* SYNOPSIS
/* #include <milter.h>
/*
/* MILTERS *milter_create(milter_names, conn_timeout, cmd_timeout,
/* msg_timeout, protocol, def_action,
/* conn_macros, helo_macros,
/* mail_macros, rcpt_macros,
/* data_macros, eoh_macros,
/* eod_macros, unk_macros,
/* macro_deflts)
/* const char *milter_names;
/* int conn_timeout;
/* int cmd_timeout;
/* int msg_timeout;
/* const char *protocol;
/* const char *def_action;
/* const char *conn_macros;
/* const char *helo_macros;
/* const char *mail_macros;
/* const char *rcpt_macrps;
/* const char *data_macros;
/* const char *eoh_macros;
/* const char *eod_macros;
/* const char *unk_macros;
/* const char *macro_deflts;
/*
/* void milter_free(milters)
/* MILTERS *milters;
/*
/* void milter_macro_callback(milters, mac_lookup, mac_context)
/* const char *(*mac_lookup)(const char *name, void *context);
/* void *mac_context;
/*
/* void milter_edit_callback(milters, add_header, upd_header,
/* ins_header, del_header, chg_from,
/* add_rcpt, add_rcpt_par, del_rcpt,
/* repl_body, context)
/* MILTERS *milters;
/* MILTER_ADD_HEADER_FN add_header;
/* MILTER_EDIT_HEADER_FN upd_header;
/* MILTER_EDIT_HEADER_FN ins_header;
/* MILTER_DEL_HEADER_FN del_header;
/* MILTER_EDIT_FROM_FN chg_from;
/* MILTER_EDIT_RCPT_FN add_rcpt;
/* MILTER_EDIT_RCPT_PAR_FN add_rcpt_par;
/* MILTER_EDIT_RCPT_FN del_rcpt;
/* MILTER_EDIT_BODY_FN repl_body;
/* void *context;
/*
/* const char *milter_conn_event(milters, client_name, client_addr,
/* client_port, addr_family)
/* MILTERS *milters;
/* const char *client_name;
/* const char *client_addr;
/* const char *client_port;
/* int addr_family;
/*
/* const char *milter_disc_event(milters)
/* MILTERS *milters;
/*
/* const char *milter_helo_event(milters, helo_name, esmtp_flag)
/* MILTERS *milters;
/* const char *helo_name;
/* int esmtp_flag;
/*
/* const char *milter_mail_event(milters, argv)
/* MILTERS *milters;
/* const char **argv;
/*
/* const char *milter_rcpt_event(milters, flags, argv)
/* MILTERS *milters;
/* int flags;
/* const char **argv;
/*
/* const char *milter_data_event(milters)
/* MILTERS *milters;
/*
/* const char *milter_unknown_event(milters, command)
/* MILTERS *milters;
/* const char *command;
/*
/* const char *milter_other_event(milters)
/* MILTERS *milters;
/*
/* const char *milter_message(milters, qfile, data_offset, auto_hdrs)
/* MILTERS *milters;
/* VSTREAM *qfile;
/* off_t data_offset;
/* ARGV *auto_hdrs;
/*
/* const char *milter_abort(milters)
/* MILTERS *milters;
/*
/* int milter_send(milters, fp)
/* MILTERS *milters;
/* VSTREAM *fp;
/*
/* MILTERS *milter_receive(fp, count)
/* VSTREAM *fp;
/* int count;
/*
/* int milter_dummy(milters, fp)
/* MILTERS *milters;
/* VSTREAM *fp;
/* DESCRIPTION
/* The functions in this module manage one or more milter (mail
/* filter) clients. Currently, only the Sendmail 8 filter
/* protocol is supported.
/*
/* The functions that inspect content or envelope commands
/* return either an SMTP reply ([45]XX followed by enhanced
/* status code and text), "D" (discard), "H" (quarantine),
/* "S" (shutdown connection), or a null pointer, which means
/* "no news is good news".
/*
/* milter_create() instantiates the milter clients specified
/* with the milter_names argument.  The conn_macros etc.
/* arguments specify the names of macros that are sent to the
/* mail filter applications upon a connect etc. event, and the
/* macro_deflts argument specifies macro defaults that will be used
/* only if the application's lookup call-back returns null. This
/* function should be called during process initialization,
/* before entering a chroot jail. The timeout parameters specify
/* time limits for the completion of the specified request
/* classes. The protocol parameter specifies a protocol version
/* and optional extensions.  When the milter application is
/* unavailable, the milter client will go into a suitable error
/* state as specified with the def_action parameter (i.e.
/* reject, tempfail or accept all subsequent events).
/*
/* milter_free() disconnects from the milter instances that
/* are still opened, and destroys the data structures created
/* by milter_create(). This function is safe to call at any
/* point after milter_create().
/*
/* milter_macro_callback() specifies a call-back function and
/* context for macro lookup. This function must be called
/* before milter_conn_event().
/*
/* milter_edit_callback() specifies call-back functions and
/* context for editing the queue file after the end-of-data
/* is received. This function must be called before milter_message();
/*
/* milter_conn_event() reports an SMTP client connection event
/* to the specified milter instances, after sending the macros
/* specified with the milter_create() conn_macros argument.
/* This function must be called before reporting any other
/* events.
/*
/* milter_disc_event() reports an SMTP client disconnection
/* event to the specified milter instances. No events can
/* reported after this call. To simplify usage, redundant calls
/* of this function are NO-OPs and don't raise a run-time
/* error.
/*
/* milter_helo_event() reports a HELO or EHLO event to the
/* specified milter instances, after sending the macros that
/* were specified with the milter_create() helo_macros argument.
/*
/* milter_mail_event() reports a MAIL FROM event to the specified
/* milter instances, after sending the macros that were specified
/* with the milter_create() mail_macros argument.
/*
/* milter_rcpt_event() reports an RCPT TO event to the specified
/* milter instances, after sending the macros that were specified
/* with the milter_create() rcpt_macros argument. The flags
/* argument supports the following:
/* .IP MILTER_FLAG_WANT_RCPT_REJ
/* When this flag is cleared, invoke all milters.  When this
/* flag is set, invoke only milters that want to receive
/* rejected recipients; with Sendmail V8 Milters, {rcpt_mailer}
/* is set to "error", {rcpt_host} is set to an enhanced status
/* code, and {rcpt_addr} is set to descriptive text.
/* .PP
/* milter_data_event() reports a DATA event to the specified
/* milter instances, after sending the macros that were specified
/* with the milter_create() data_macros argument.
/*
/* milter_unknown_event() reports an unknown command event to
/* the specified milter instances, after sending the macros
/* that were specified with the milter_create() unk_macros
/* argument.
/*
/* milter_other_event() returns the current default mail filter
/* reply for the current SMTP connection state; it does not
/* change milter states. A null pointer result means that all
/* is well. This function can be used for SMTP commands such
/* as AUTH, STARTTLS that don't have their own milter event
/* routine.
/*
/* milter_message() sends the message header and body to the
/* to the specified milter instances, and sends the macros
/* specified with the milter_create() eoh_macros after the
/* message header, and with the eod_macros argument at
/* the end.  Each milter sees the result of any changes made
/* by a preceding milter. This function must be called with
/* as argument an open Postfix queue file.
/*
/* milter_abort() cancels a mail transaction in progress.  To
/* simplify usage, redundant calls of this function are NO-OPs
/* and don't raise a run-time error.
/*
/* milter_send() sends a list of mail filters over the specified
/* stream. When given a null list pointer, a "no filter"
/* indication is sent.  The result is non-zero in case of
/* error.
/*
/* milter_receive() receives the specified number of mail
/* filters over the specified stream. The result is a null
/* pointer when no milters were sent, or when an error happened.
/*
/* milter_dummy() is like milter_send(), except that it sends
/* a dummy, but entirely valid, mail filter list.
/* SEE ALSO
/* milter8(3) Sendmail 8 Milter protocol
/* DIAGNOSTICS
/* Panic: interface violation.
/* Fatal errors: memory allocation problem.
/* 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>

/* Utility library. */

#include <msg.h>
#include <mymalloc.h>
#include <stringops.h>
#include <argv.h>
#include <attr.h>
#include <htable.h>

/* Global library. */

#include <mail_proto.h>
#include <record.h>
#include <rec_type.h>
#include <mail_params.h>
#include <attr_override.h>

/* Postfix Milter library. */

#include <milter.h>

/* Application-specific. */

 /*
  * SLMs.
  */

#define STR(x) vstring_str(x)

/* milter_macro_defaults_create - parse default macro entries */

HTABLE *milter_macro_defaults_create(const char *macro_defaults)
{
    const char myname[] = "milter_macro_defaults_create";
    char   *saved_defaults = mystrdup(macro_defaults);
    char   *cp = saved_defaults;
    HTABLE *table = 0;
    VSTRING *canon_buf = 0;
    char   *nameval;

    while ((nameval = mystrtokq(&cp, CHARS_COMMA_SP, CHARS_BRACE)) != 0) {
 const char *err;
 char   *name;
 char   *value;

 /*
  * Split the input into (name, value) pairs. Allow the forms
  * name=value and  { name = value }, where the last form ignores
  * whitespace after the opening "{", around the "=", and before the
  * closing "}". A name may also be specified as {name}.
  * 
  * Use the form {name} for table lookups, because that is the form of
  * the S8_MAC_* macro names.
 */

 if (*nameval == CHARS_BRACE[0]
     && nameval[balpar(nameval, CHARS_BRACE)] != '='
     && (err = extpar(&nameval, CHARS_BRACE, EXTPAR_FLAG_NONE)) != 0)
     msg_fatal("malformed default macro entry: %s in \"%s\"",
        err, macro_defaults);
 if ((err = split_nameval(nameval, &name, &value)) != 0)
     msg_fatal("malformed default macro entry: %s in \"%s\"",
        err, macro_defaults);
 if (*name != '{')   /* } */
     name = STR(vstring_sprintf(canon_buf ? canon_buf :
       (canon_buf = vstring_alloc(20)), "{%s}", name));
 if (table == 0)
     table = htable_create(1);
 if (htable_find(table, name) != 0) {
     msg_warn("ignoring multiple default macro entries for %s in \"%s\"",
       name, macro_defaults);
 } else {
     (void) htable_enter(table, name, mystrdup(value));
     if (msg_verbose)
  msg_info("%s: add name=%s default=%s", myname, name, value);
 }
    }
    myfree(saved_defaults);
    if (canon_buf)
 vstring_free(canon_buf);
    return (table);
}

/* milter_macro_lookup - look up macros */

static ARGV *milter_macro_lookup(MILTERS *milters, const char *macro_names)
{
    const char *myname = "milter_macro_lookup";
    char   *saved_names = mystrdup(macro_names);
    char   *cp = saved_names;
    ARGV   *argv = argv_alloc(10);
    VSTRING *canon_buf = vstring_alloc(20);
    const char *value;
    const char *name;
    const char *cname;

    while ((name = mystrtok(&cp, CHARS_COMMA_SP)) != 0) {
 if (msg_verbose)
     msg_info("%s: \"%s\"", myname, name);
 if (*name != '{')   /* } */
     cname = STR(vstring_sprintf(canon_buf, "{%s}", name));
 else
     cname = name;
 if ((value = milters->mac_lookup(cname, milters->mac_context)) != 0) {
     if (msg_verbose)
  msg_info("%s: result \"%s\"", myname, value);
     argv_add(argv, name, value, (char *) 0);
 } else if (milters->macro_defaults != 0
     && (value = htable_find(milters->macro_defaults, cname)) != 0) {
     if (msg_verbose)
  msg_info("%s: using default \"%s\"", myname, value);
     argv_add(argv, name, value, (char *) 0);
 }
    }
    myfree(saved_names);
    vstring_free(canon_buf);
    return (argv);
}

/* milter_macro_callback - specify macro lookup */

void    milter_macro_callback(MILTERS *milters,
             const char *(*mac_lookup) (const char *, void *),
                 void *mac_context)
{
    milters->mac_lookup = mac_lookup;
    milters->mac_context = mac_context;
}

/* milter_edit_callback - specify queue file edit call-back information */

void    milter_edit_callback(MILTERS *milters,
                MILTER_ADD_HEADER_FN add_header,
                MILTER_EDIT_HEADER_FN upd_header,
                MILTER_EDIT_HEADER_FN ins_header,
                MILTER_DEL_HEADER_FN del_header,
                MILTER_EDIT_FROM_FN chg_from,
                MILTER_EDIT_RCPT_FN add_rcpt,
                MILTER_EDIT_RCPT_PAR_FN add_rcpt_par,
                MILTER_EDIT_RCPT_FN del_rcpt,
                MILTER_EDIT_BODY_FN repl_body,
                void *chg_context)
{
    milters->add_header = add_header;
    milters->upd_header = upd_header;
    milters->ins_header = ins_header;
    milters->del_header = del_header;
    milters->chg_from = chg_from;
    milters->add_rcpt = add_rcpt;
    milters->add_rcpt_par = add_rcpt_par;
    milters->del_rcpt = del_rcpt;
    milters->repl_body = repl_body;
    milters->chg_context = chg_context;
}

/* milter_conn_event - report connect event */

const char *milter_conn_event(MILTERS *milters,
                 const char *client_name,
                 const char *client_addr,
                 const char *client_port,
                 unsigned addr_family)
{
    const char *resp;
    MILTER *m;
    ARGV   *global_macros = 0;
    ARGV   *any_macros;

#define MILTER_MACRO_EVAL(global_macros, m, milters, member) \
 ((m->macros && m->macros->member[0]) ? \
     milter_macro_lookup(milters, m->macros->member) : \
  global_macros ? global_macros : \
      (global_macros = \
           milter_macro_lookup(milters, milters->macros->member)))

    if (msg_verbose)
 msg_info("report connect to all milters");
    for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next) {
 if (m->connect_on_demand != 0)
     m->connect_on_demand(m);
 any_macros = MILTER_MACRO_EVAL(global_macros, m, milters, conn_macros);
 resp = m->conn_event(m, client_name, client_addr, client_port,
        addr_family, any_macros);
 if (any_macros != global_macros)
     argv_free(any_macros);
    }
    if (global_macros)
 argv_free(global_macros);
    return (resp);
}

/* milter_helo_event - report helo event */

const char *milter_helo_event(MILTERS *milters, const char *helo_name,
                 int esmtp_flag)
{
    const char *resp;
    MILTER *m;
    ARGV   *global_macros = 0;
    ARGV   *any_macros;

    if (msg_verbose)
 msg_info("report helo to all milters");
    for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next) {
 any_macros = MILTER_MACRO_EVAL(global_macros, m, milters, helo_macros);
 resp = m->helo_event(m, helo_name, esmtp_flag, any_macros);
 if (any_macros != global_macros)
     argv_free(any_macros);
    }
    if (global_macros)
 argv_free(global_macros);
    return (resp);
}

/* milter_mail_event - report mail from event */

const char *milter_mail_event(MILTERS *milters, const char **argv)
{
    const char *resp;
    MILTER *m;
    ARGV   *global_macros = 0;
    ARGV   *any_macros;

    if (msg_verbose)
 msg_info("report sender to all milters");
    for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next) {
 any_macros = MILTER_MACRO_EVAL(global_macros, m, milters, mail_macros);
 resp = m->mail_event(m, argv, any_macros);
 if (any_macros != global_macros)
     argv_free(any_macros);
    }
    if (global_macros)
 argv_free(global_macros);
    return (resp);
}

/* milter_rcpt_event - report rcpt to event */

const char *milter_rcpt_event(MILTERS *milters, int flags, const char **argv)
{
    const char *resp;
    MILTER *m;
    ARGV   *global_macros = 0;
    ARGV   *any_macros;

    if (msg_verbose)
 msg_info("report recipient to all milters (flags=0x%x)", flags);
    for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next) {
 if ((flags & MILTER_FLAG_WANT_RCPT_REJ) == 0
     || (m->flags & MILTER_FLAG_WANT_RCPT_REJ) != 0) {
     any_macros =
  MILTER_MACRO_EVAL(global_macros, m, milters, rcpt_macros);
     resp = m->rcpt_event(m, argv, any_macros);
     if (any_macros != global_macros)
  argv_free(any_macros);
 }
    }
    if (global_macros)
 argv_free(global_macros);
    return (resp);
}

/* milter_data_event - report data event */

const char *milter_data_event(MILTERS *milters)
{
    const char *resp;
    MILTER *m;
    ARGV   *global_macros = 0;
    ARGV   *any_macros;

    if (msg_verbose)
 msg_info("report data to all milters");
    for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next) {
 any_macros = MILTER_MACRO_EVAL(global_macros, m, milters, data_macros);
 resp = m->data_event(m, any_macros);
 if (any_macros != global_macros)
     argv_free(any_macros);
    }
    if (global_macros)
 argv_free(global_macros);
    return (resp);
}

/* milter_unknown_event - report unknown command */

const char *milter_unknown_event(MILTERS *milters, const char *command)
{
    const char *resp;
    MILTER *m;
    ARGV   *global_macros = 0;
    ARGV   *any_macros;

    if (msg_verbose)
 msg_info("report unknown command to all milters");
    for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next) {
 any_macros = MILTER_MACRO_EVAL(global_macros, m, milters, unk_macros);
 resp = m->unknown_event(m, command, any_macros);
 if (any_macros != global_macros)
     argv_free(any_macros);
    }
    if (global_macros)
 argv_free(global_macros);
    return (resp);
}

/* milter_other_event - other SMTP event */

const char *milter_other_event(MILTERS *milters)
{
    const char *resp;
    MILTER *m;

    if (msg_verbose)
 msg_info("query milter states for other event");
    for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next)
 resp = m->other_event(m);
    return (resp);
}

/* milter_message - inspect message content */

const char *milter_message(MILTERS *milters, VSTREAM *fp, off_t data_offset,
              ARGV *auto_hdrs)
{
    const char *resp;
    MILTER *m;
    ARGV   *global_eoh_macros = 0;
    ARGV   *global_eod_macros = 0;
    ARGV   *any_eoh_macros;
    ARGV   *any_eod_macros;

    if (msg_verbose)
 msg_info("inspect content by all milters");
    for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next) {
 any_eoh_macros = MILTER_MACRO_EVAL(global_eoh_macros, m, milters, eoh_macros);
 any_eod_macros = MILTER_MACRO_EVAL(global_eod_macros, m, milters, eod_macros);
 resp = m->message(m, fp, data_offset, any_eoh_macros, any_eod_macros,
     auto_hdrs);
 if (any_eoh_macros != global_eoh_macros)
     argv_free(any_eoh_macros);
 if (any_eod_macros != global_eod_macros)
     argv_free(any_eod_macros);
    }
    if (global_eoh_macros)
 argv_free(global_eoh_macros);
    if (global_eod_macros)
 argv_free(global_eod_macros);
    return (resp);
}

/* milter_abort - cancel message receiving state, all milters */

void    milter_abort(MILTERS *milters)
{
    MILTER *m;

    if (msg_verbose)
 msg_info("abort all milters");
    for (m = milters->milter_list; m != 0; m = m->next)
 m->abort(m);
}

/* milter_disc_event - report client disconnect event to all milters */

void    milter_disc_event(MILTERS *milters)
{
    MILTER *m;

    if (msg_verbose)
 msg_info("disconnect event to all milters");
    for (m = milters->milter_list; m != 0; m = m->next)
 m->disc_event(m);
}

 /*
  * Table-driven parsing of main.cf parameter overrides for specific Milters.
  * We derive the override names from the corresponding main.cf parameter
  * names by skipping the redundant "milter_" prefix.
  */

static ATTR_OVER_TIME time_table[] = {
    7 + (const char *) VAR_MILT_CONN_TIME, DEF_MILT_CONN_TIME, 010,
    7 + (const char *) VAR_MILT_CMD_TIME, DEF_MILT_CMD_TIME, 010,
    7 + (const char *) VAR_MILT_MSG_TIME, DEF_MILT_MSG_TIME, 010,
    0,
};
static ATTR_OVER_STR str_table[] = {
    7 + (const char *) VAR_MILT_PROTOCOL, 010,
    7 + (const char *) VAR_MILT_DEF_ACTION, 010,
    0,
};

#define link_override_table_to_variable(table, var) \
 do { table[var##_offset].target = &var; } while (0)

#define my_conn_timeout_offset 0
#define my_cmd_timeout_offset 1
#define my_msg_timeout_offset 2

#define my_protocol_offset 0
#define my_def_action_offset 1

/* milter_new - create milter list */

MILTERS *milter_new(const char *names,
              int conn_timeout,
              int cmd_timeout,
              int msg_timeout,
              const char *protocol,
              const char *def_action,
              MILTER_MACROS *macros,
              HTABLE *macro_defaults)
{
    MILTERS *milters;
    MILTER *head = 0;
    MILTER *tail = 0;
    char   *name;
    MILTER *milter;
    const char *sep = CHARS_COMMA_SP;
    const char *parens = CHARS_BRACE;
    int     my_conn_timeout;
    int     my_cmd_timeout;
    int     my_msg_timeout;
    const char *my_protocol;
    const char *my_def_action;

    /*
     * Initialize.
     */

    link_override_table_to_variable(time_table, my_conn_timeout);
    link_override_table_to_variable(time_table, my_cmd_timeout);
    link_override_table_to_variable(time_table, my_msg_timeout);
    link_override_table_to_variable(str_table, my_protocol);
    link_override_table_to_variable(str_table, my_def_action);

    /*
     * Parse the milter list.
     */

    milters = (MILTERS *) mymalloc(sizeof(*milters));
    if (names != 0 && *names != 0) {
 char   *saved_names = mystrdup(names);
 char   *cp = saved_names;
 char   *op;
 char   *err;

 /*
  * Instantiate Milters, allowing for per-Milter overrides.
 */

 while ((name = mystrtokq(&cp, sep, parens)) != 0) {
     my_conn_timeout = conn_timeout;
     my_cmd_timeout = cmd_timeout;
     my_msg_timeout = msg_timeout;
     my_protocol = protocol;
     my_def_action = def_action;
     if (name[0] == parens[0]) {
  op = name;
  if ((err = extpar(&op, parens, EXTPAR_FLAG_NONE)) != 0)
      msg_fatal("milter service syntax error: %s", err);
  if ((name = mystrtok(&op, sep)) == 0)
      msg_fatal("empty milter definition: \"%s\"", names);
  attr_override(op, sep, parens,
         CA_ATTR_OVER_STR_TABLE(str_table),
         CA_ATTR_OVER_TIME_TABLE(time_table),
         CA_ATTR_OVER_END);
     }
     milter = milter8_create(name, my_conn_timeout, my_cmd_timeout,
        my_msg_timeout, my_protocol,
        my_def_action, milters);
     if (head == 0) {
  head = milter;
     } else {
  tail->next = milter;
     }
     tail = milter;
 }
 myfree(saved_names);
    }
    milters->milter_list = head;
    milters->mac_lookup = 0;
    milters->mac_context = 0;
    milters->macros = macros;
    milters->macro_defaults = macro_defaults;
    milters->add_header = 0;
    milters->upd_header = milters->ins_header = 0;
    milters->del_header = 0;
    milters->add_rcpt = milters->del_rcpt = 0;
    milters->repl_body = 0;
    milters->chg_context = 0;
    return (milters);
}

/* milter_free - destroy all milters */

void    milter_free(MILTERS *milters)
{
    MILTER *m;
    MILTER *next;

    if (msg_verbose)
 msg_info("free all milters");
    for (m = milters->milter_list; m != 0; m = next)
 next = m->next, m->free(m);
    if (milters->macros)
 milter_macros_free(milters->macros);
    if (milters->macro_defaults)
 htable_free(milters->macro_defaults, myfree);
    myfree((void *) milters);
}

/* milter_dummy - send empty milter list */

int     milter_dummy(MILTERS *milters, VSTREAM *stream)
{
    MILTERS dummy = *milters;

    dummy.milter_list = 0;
    return (milter_send(&dummy, stream));
}

/* milter_send - send Milter instances over stream */

int     milter_send(MILTERS *milters, VSTREAM *stream)
{
    MILTER *m;
    int     status = 0;
    int     count = 0;

    /*
     * XXX Optimization: send only the filters that are actually used in the
     * remote process. No point sending a filter that looks at HELO commands
     * to a cleanup server. For now we skip only the filters that are known
     * to be disabled (either in global error state or in global accept
     * state).
     * 
     * XXX We must send *some* information, even when there are no active
     * filters, otherwise the cleanup server would try to apply its own
     * non_smtpd_milters settings.
     */

    if (milters != 0)
 for (m = milters->milter_list; m != 0; m = m->next)
     if (m->active(m))
  count++;
    (void) rec_fprintf(stream, REC_TYPE_MILT_COUNT, "%d", count);

    if (msg_verbose)
 msg_info("send %d milters", count);

    /*
     * XXX Optimization: don't send or receive further information when there
     * aren't any active filters.
     */

    if (count <= 0)
 return (0);

    /*
     * Send the filter macro name lists.
     */

    (void) attr_print(stream, ATTR_FLAG_MORE,
        SEND_ATTR_FUNC(milter_macros_print,
         (const void *) milters->macros),
        ATTR_TYPE_END);

    /*
     * Send the filter macro defaults.
     */

    count = milters->macro_defaults ? milters->macro_defaults->used : 0;
    (void) attr_print(stream, ATTR_FLAG_MORE,
        SEND_ATTR_INT(MAIL_ATTR_SIZE, count),
        ATTR_TYPE_END);
    if (count > 0)
 (void) attr_print(stream, ATTR_FLAG_MORE,
     SEND_ATTR_HASH(milters->macro_defaults),
     ATTR_TYPE_END);

    /*
     * Send the filter instances.
     */

    for (m = milters->milter_list; m != 0; m = m->next)
 if (m->active(m) && (status = m->send(m, stream)) != 0)
     break;

    /*
     * Over to you.
     */

    if (status != 0
 || attr_scan(stream, ATTR_FLAG_STRICT,
       RECV_ATTR_INT(MAIL_ATTR_STATUS, &status),
       ATTR_TYPE_END) != 1
 || status != 0) {
 msg_warn("cannot send milters to service %s", VSTREAM_PATH(stream));
 return (-1);
    }
    return (0);
}

/* milter_receive - receive milters from stream */

MILTERS *milter_receive(VSTREAM *stream, int count)
{
    MILTERS *milters;
    MILTER *head = 0;
    MILTER *tail = 0;
    MILTER *milter = 0;
    int     macro_default_count;

    if (msg_verbose)
 msg_info("receive %d milters", count);

    /*
     * XXX We must instantiate a MILTERS structure even when the sender has
     * no active filters, otherwise the cleanup server would try to use its
     * own non_smtpd_milters settings.
     */

#define NO_MILTERS ((char *) 0)
#define NO_TIMEOUTS 000
#define NO_PROTOCOL ((char *) 0)
#define NO_ACTION ((char *) 0)
#define NO_MACROS ((MILTER_MACROS *) 0)
#define NO_MACRO_DEFLTS ((HTABLE *) 0)

    milters = milter_new(NO_MILTERS, NO_TIMEOUTS, NO_PROTOCOL, NO_ACTION,
    NO_MACROS, NO_MACRO_DEFLTS);

    /*
     * XXX Optimization: don't send or receive further information when there
     * aren't any active filters.
     */

    if (count <= 0)
 return (milters);

    /*
     * Receive the global macro name lists.
     */

    milters->macros = milter_macros_alloc(MILTER_MACROS_ALLOC_ZERO);
    if (attr_scan(stream, ATTR_FLAG_STRICT | ATTR_FLAG_MORE,
    RECV_ATTR_FUNC(milter_macros_scan,
     (void *) milters->macros),
    ATTR_TYPE_END) != 1) {
 milter_free(milters);
 return (0);
    }

    /*
     * Receive the filter macro defaults.
     */

    if (attr_scan(stream, ATTR_FLAG_STRICT | ATTR_FLAG_MORE,
    RECV_ATTR_INT(MAIL_ATTR_SIZE, ¯o_default_count),
    ATTR_TYPE_END) != 1
 || (macro_default_count > 0
     && attr_scan(stream, ATTR_FLAG_STRICT | ATTR_FLAG_MORE,
    RECV_ATTR_HASH(milters->macro_defaults
     = htable_create(1)),
    ATTR_TYPE_END) != macro_default_count)) {
 milter_free(milters);
 return (0);
    }

    /*
     * Receive the filters.
     */

    for (; count > 0; count--) {
 if ((milter = milter8_receive(stream, milters)) == 0) {
     msg_warn("cannot receive milters via service %s socket",
       VSTREAM_PATH(stream));
     milter_free(milters);
     return (0);
 }
 if (head == 0) {
     /* Coverity: milter_free() depends on milters->milter_list. */
     milters->milter_list = head = milter;
 } else {
     tail->next = milter;
 }
 tail = milter;
    }

    /*
     * Over to you.
     */

    (void) attr_print(stream, ATTR_FLAG_NONE,
        SEND_ATTR_INT(MAIL_ATTR_STATUS, 0),
        ATTR_TYPE_END);
    return (milters);
}

#ifdef TEST

 /*
  * Proof-of-concept test program. This can be used interactively, but is
  * typically used for automated regression tests from a script.
  */


/* System library. */

#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>

/* Utility library. */

#include "msg_vstream.h"
#include "vstring_vstream.h"

/* Global library. */

#include <mail_params.h>

int     var_milt_conn_time = 10;
int     var_milt_cmd_time = 10;
int     var_milt_msg_time = 100;
char   *var_milt_protocol = DEF_MILT_PROTOCOL;
char   *var_milt_def_action = DEF_MILT_DEF_ACTION;

static void usage(void)
{
    vstream_fprintf(VSTREAM_ERR, "usage: \n"
      " create names...  create and connect\n"
#if 0
      " conn_macros names... define connect macros\n"
      " helo_macros names... define helo command macros\n"
      " mail_macros names... define mail command macros\n"
      " rcpt_macros names... define rcpt command macros\n"
      " data_macros names... define data command macros\n"
      " unk_macros names... unknown command macros\n"
      " message_macros names... define message macros\n"
#endif
      " free   disconnect and destroy\n"
      " connect name addr port family\n"
      " helo hostname\n"
      " ehlo hostname\n"
      " mail from sender...\n"
      " rcpt to recipient...\n"
      " data\n"
      " disconnect\n"
      " unknown command\n");
    vstream_fflush(VSTREAM_ERR);
}

int     main(int argc, char **argv)
{
    MILTERS *milters = 0;
    char   *conn_macros, *helo_macros, *mail_macros, *rcpt_macros;
    char   *data_macros, *eoh_macros, *eod_macros, *unk_macros;
    char   *macro_deflts;
    VSTRING *inbuf = vstring_alloc(100);
    char   *bufp;
    char   *cmd;
    int     ch;
    int     istty = isatty(vstream_fileno(VSTREAM_IN));

    conn_macros = helo_macros = mail_macros = rcpt_macros = data_macros
 = eoh_macros = eod_macros = unk_macros = macro_deflts = "";

    msg_vstream_init(argv[0], VSTREAM_ERR);
    while ((ch = GETOPT(argc, argv, "V:v")) > 0) {
 switch (ch) {
 default:
     msg_fatal("usage: %s [-a action] [-p protocol] [-v]", argv[0]);
 case 'a':
     var_milt_def_action = optarg;
     break;
 case 'p':
     var_milt_protocol = optarg;
     break;
 case 'v':
     msg_verbose++;
     break;
 }
    }
    optind = OPTIND;

    for (;;) {
 const char *resp = 0;
 ARGV   *argv;
 char  **args;

 if (istty) {
     vstream_printf("- ");
     vstream_fflush(VSTREAM_OUT);
 }
 if (vstring_fgets_nonl(inbuf, VSTREAM_IN) <= 0)
     break;
 bufp = vstring_str(inbuf);
 if (!istty) {
     vstream_printf("> %s\n", bufp);
     vstream_fflush(VSTREAM_OUT);
 }
 if (*bufp == '#')
     continue;
 cmd = mystrtok(&bufp, " ");
 if (cmd == 0) {
     usage();
     continue;
 }
 argv = argv_split(bufp, " ");
 args = argv->argv;
 if (strcmp(cmd, "create") == 0 && argv->argc == 1) {
     if (milters != 0) {
  msg_warn("deleting existing milters");
  milter_free(milters);
     }
     milters = milter_create(args[0], var_milt_conn_time,
        var_milt_cmd_time, var_milt_msg_time,
        var_milt_protocol, var_milt_def_action,
        conn_macros, helo_macros, mail_macros,
        rcpt_macros, data_macros, eoh_macros,
        eod_macros, unk_macros, macro_deflts);
 } else if (strcmp(cmd, "free") == 0 && argv->argc == 0) {
     if (milters == 0) {
  msg_warn("no milters");
  continue;
     }
     milter_free(milters);
     milters = 0;
 } else if (strcmp(cmd, "connect") == 0 && argv->argc == 4) {
     if (milters == 0) {
  msg_warn("no milters");
  continue;
     }
     resp = milter_conn_event(milters, args[0], args[1], args[2],
     strcmp(args[3], "AF_INET") == 0 ? AF_INET :
          strcmp(args[3], "AF_INET6") == 0 ? AF_INET6 :
     strcmp(args[3], "AF_UNIX") == 0 ? AF_UNIX :
         AF_UNSPEC);
 } else if (strcmp(cmd, "helo") == 0 && argv->argc == 1) {
     if (milters == 0) {
  msg_warn("no milters");
  continue;
     }
     resp = milter_helo_event(milters, args[0], 0);
 } else if (strcmp(cmd, "ehlo") == 0 && argv->argc == 1) {
     if (milters == 0) {
  msg_warn("no milters");
  continue;
     }
     resp = milter_helo_event(milters, args[0], 1);
 } else if (strcmp(cmd, "mail") == 0 && argv->argc > 0) {
     if (milters == 0) {
  msg_warn("no milters");
  continue;
     }
     resp = milter_mail_event(milters, (const char **) args);
 } else if (strcmp(cmd, "rcpt") == 0 && argv->argc > 0) {
     if (milters == 0) {
  msg_warn("no milters");
  continue;
     }
     resp = milter_rcpt_event(milters, 0, (const char **) args);
 } else if (strcmp(cmd, "unknown") == 0 && argv->argc > 0) {
     if (milters == 0) {
  msg_warn("no milters");
  continue;
     }
     resp = milter_unknown_event(milters, args[0]);
 } else if (strcmp(cmd, "data") == 0 && argv->argc == 0) {
     if (milters == 0) {
  msg_warn("no milters");
  continue;
     }
     resp = milter_data_event(milters);
 } else if (strcmp(cmd, "disconnect") == 0 && argv->argc == 0) {
     if (milters == 0) {
  msg_warn("no milters");
  continue;
     }
     milter_disc_event(milters);
 } else {
     usage();
 }
 if (resp != 0)
     msg_info("%s", resp);
 argv_free(argv);
    }
    if (milters != 0)
 milter_free(milters);
    vstring_free(inbuf);
    return (0);
}

#endif

Messung V0.5 in Prozent
C=76 H=90 G=83

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

*© 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