Eine aufbereitete Darstellung der Quelle

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

Benutzer

Quelle  header_body_checks.c

  Sprache: C
 

/*++
/* NAME
/* header_body_checks 3
/* SUMMARY
/* header/body checks
/* SYNOPSIS
/* #include <header_body_checks.h>
/*
/* typedef struct {
/* void (*logger) (void *context, const char *action,
/* const char *where, const char *line,
/* const char *optional_text);
/* void (*prepend) (void *context, int rec_type,
/* const char *buf, ssize_t len, off_t offset);
/* char *(*extend) (void *context, const char *command,
/* ssize_t cmd_len, const char *cmd_args,
/* const char *where, const char *line,
/* ssize_t line_len, off_t offset);
/* } HBC_CALL_BACKS;
/*
/* HBC_CHECKS *hbc_header_checks_create(
/* header_checks_name, header_checks_value
/* mime_header_checks_name, mime_header_checks_value,
/* nested_header_checks_name, nested_header_checks_value,
/* call_backs)
/* const char *header_checks_name;
/* const char *header_checks_value;
/* const char *mime_header_checks_name;
/* const char *mime_header_checks_value;
/* const char *nested_header_checks_name;
/* const char *nested_header_checks_value;
/* HBC_CALL_BACKS *call_backs;
/*
/* HBC_CHECKS *hbc_body_checks_create(
/* body_checks_name, body_checks_value,
/* call_backs)
/* const char *body_checks_name;
/* const char *body_checks_value;
/* HBC_CALL_BACKS *call_backs;
/*
/* char *hbc_header_checks(context, hbc, header_class, hdr_opts, header)
/* void *context;
/* HBC_CHECKS *hbc;
/* int header_class;
/* const HEADER_OPTS *hdr_opts;
/* VSTRING *header;
/*
/* char *hbc_body_checks(context, hbc, body_line, body_line_len)
/* void *context;
/* HBC_CHECKS *hbc;
/* const char *body_line;
/* ssize_t body_line_len;
/*
/* void hbc_header_checks_free(hbc)
/* HBC_CHECKS *hbc;
/*
/* void hbc_body_checks_free(hbc)
/* HBC_CHECKS *hbc;
/* DESCRIPTION
/* This module implements header_checks and body_checks.
/* Actions are executed while mail is being delivered. The
/* following actions are recognized: INFO, WARN, REPLACE,
/* PREPEND, IGNORE, DUNNO, and OK. These actions are safe for
/* use in delivery agents.
/*
/* Other actions may be supplied via the extension mechanism
/* described below.  For example, actions that change the
/* message delivery time or destination. Such actions do not
/* make sense in delivery agents, but they can be appropriate
/* in, for example, before-queue filters.
/*
/* hbc_header_checks_create() creates a context for header
/* inspection. This function is typically called once during
/* program initialization.  The result is a null pointer when
/* all _value arguments specify zero-length strings; in this
/* case, hbc_header_checks() and hbc_header_checks_free() must
/* not be called.
/*
/* hbc_header_checks() inspects the specified logical header.
/* The result is either the original header, HBC_CHECKS_STAT_IGNORE
/* (meaning: discard the header), HBC_CHECKS_STAT_ERROR, or a
/* new header (meaning: replace the header and destroy the new
/* header with myfree()).
/*
/* hbc_header_checks_free() returns memory to the pool.
/*
/* hbc_body_checks_create(), hbc_body_checks(), hbc_body_free()
/* perform similar functions for body lines.
/*
/* Arguments:
/* .IP body_line
/* One line of body text.
/* .IP body_line_len
/* Body line length.
/* .IP call_backs
/* Table with call-back function pointers. This argument is
/* not copied.  Note: the description below is not necessarily
/* in data structure order.
/* .RS
/* .IP logger
/* Call-back function for logging an action with the action's
/* name in lower case, a location within a message ("header"
/* or "body"), the content of the header or body line that
/* triggered the action, and optional text or a zero-length
/* string. This call-back feature must be specified.
/* .IP prepend
/* Call-back function for the PREPEND action. The arguments
/* are the same as those of mime_state(3) body output call-back
/* functions.  Specify a null pointer to disable this action.
/* .IP extend
/* Call-back function that logs and executes other actions.
/* This function receives as arguments the command name and
/* name length, the command arguments if any, the location
/* within the message ("header" or "body"), the content and
/* length of the header or body line that triggered the action,
/* and the input byte offset within the current header or body
/* segment.  The result value is either the original line
/* argument, HBC_CHECKS_STAT_IGNORE (delete the line from the
/* input stream) or HBC_CHECKS_STAT_UNKNOWN (the command was
/* not recognized).  Specify a null pointer to disable this
/* feature.
/* .RE
/* .IP context
/* Application context for call-back functions specified with the
/* call_backs argument.
/* .IP header
/* A logical message header. Lines within a multi-line header
/* are separated by a newline character.
/* .IP "header_checks_name, mime_header_checks_name"
/* .IP "nested_header_checks_name, body_checks_name"
/* The main.cf configuration parameter names for header and body
/* map lists.
/* .IP "header_checks_value, mime_header_checks_value"
/* .IP "nested_header_checks_value, body_checks_value"
/* The values of main.cf configuration parameters for header and body
/* map lists. Specify a zero-length string to disable a specific list.
/* .IP header_class
/* A number in the range MIME_HDR_FIRST..MIME_HDR_LAST.
/* .IP hbc
/* A handle created with hbc_header_checks_create() or
/* hbc_body_checks_create().
/* .IP hdr_opts
/* Message header properties.
/* SEE ALSO
/* msg(3) diagnostics interface
/* DIAGNOSTICS
/* 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>
#include <ctype.h>
#include <string.h>
#ifdef STRCASECMP_IN_STRINGS_H
#include <strings.h>
#endif

/* Utility library. */

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

/* Global library. */

#include <mime_state.h>
#include <rec_type.h>
#include <is_header.h>
#include <cleanup_user.h>
#include <dsn_util.h>
#include <header_body_checks.h>

/* Application-specific. */

 /*
  * Something that is guaranteed to be different from a real string result
  * from header/body_checks.
  */

char    hbc_checks_error;
const char hbc_checks_unknown;

 /*
  * Header checks are stored as an array of HBC_MAP_INFO structures, one
  * structure for each header class (MIME_HDR_PRIMARY, MIME_HDR_MULTIPART, or
  * MIME_HDR_NESTED).
  * 
  * Body checks are stored as one single HBC_MAP_INFO structure, because we make
  * no distinction between body segments.
  */

#define HBC_HEADER_INDEX(class) ((class) - MIME_HDR_FIRST)
#define HBC_BODY_INDEX (0)

#define HBC_INIT(hbc, index, name, value) do { \
 HBC_MAP_INFO *_mp = (hbc)->map_info + (index); \
 if (*(value) != 0) { \
     _mp->map_class = (name); \
     _mp->maps = maps_create((name), (value), DICT_FLAG_LOCK); \
 } else { \
     _mp->map_class = 0; \
     _mp->maps = 0; \
 } \
    } while (0)

/* How does the action routine know where we are? */

#define HBC_CTXT_HEADER "header"
#define HBC_CTXT_BODY "body"

/* Silly little macros. */

#define STR(x) vstring_str(x)
#define LEN(x) VSTRING_LEN(x)

/* hbc_action - act upon a header/body match */

static char *hbc_action(void *context, HBC_CALL_BACKS *cb,
           const char *map_class, const char *where,
           const char *cmd, const char *line,
           ssize_t line_len, off_t offset)
{
    const char *cmd_args = cmd + strcspn(cmd, " \t");
    ssize_t cmd_len = cmd_args - cmd;
    char   *ret;

    /*
     * XXX We don't use a hash table for action lookup. Mail rarely triggers
     * an action, and mail that triggers multiple actions is even rarer.
     * Setting up the hash table costs more than we would gain from using it.
     */

    while (*cmd_args && ISSPACE(*cmd_args))
 cmd_args++;

#define STREQUAL(x,y,l) (strncasecmp((x), (y), (l)) == 0 && (y)[l] == 0)

    if (cb->extend
 && (ret = cb->extend(context, cmd, cmd_len, cmd_args, where, line,
        line_len, offset)) != HBC_CHECKS_STAT_UNKNOWN)
 return (ret);

    if (STREQUAL(cmd, "WARN", cmd_len)) {
 cb->logger(context, "warning", where, line, cmd_args);
 return ((char *) line);
    }
    if (STREQUAL(cmd, "INFO", cmd_len)) {
 cb->logger(context, "info", where, line, cmd_args);
 return ((char *) line);
    }
    if (STREQUAL(cmd, "REPLACE", cmd_len)) {
 if (*cmd_args == 0) {
     msg_warn("REPLACE action without text in %s map", map_class);
     return ((char *) line);
 } else if (strcmp(where, HBC_CTXT_HEADER) == 0
     && !is_header(cmd_args)) {
     msg_warn("bad REPLACE header text \"%s\" in %s map -- "
     "need \"headername: headervalue\"", cmd_args, map_class);
     return ((char *) line);
 } else {
     cb->logger(context, "replace", where, line, cmd_args);
     return (mystrdup(cmd_args));
 }
    }
    if (cb->prepend && STREQUAL(cmd, "PREPEND", cmd_len)) {
 if (*cmd_args == 0) {
     msg_warn("PREPEND action without text in %s map", map_class);
 } else if (strcmp(where, HBC_CTXT_HEADER) == 0
     && !is_header(cmd_args)) {
     msg_warn("bad PREPEND header text \"%s\" in %s map -- "
     "need \"headername: headervalue\"", cmd_args, map_class);
 } else {
     cb->logger(context, "prepend", where, line, cmd_args);
     cb->prepend(context, REC_TYPE_NORM, cmd_args, strlen(cmd_args), offset);
 }
 return ((char *) line);
    }
    if (STREQUAL(cmd, "STRIP", cmd_len)) {
 cb->logger(context, "strip", where, line, cmd_args);
 return (HBC_CHECKS_STAT_IGNORE);
    }
    /* Allow and ignore optional text after the action. */

    if (STREQUAL(cmd, "IGNORE", cmd_len))
 /* XXX Not logged for compatibility with cleanup(8). */
 return (HBC_CHECKS_STAT_IGNORE);

    if (STREQUAL(cmd, "DUNNO", cmd_len)  /* preferred */
 ||STREQUAL(cmd, "OK", cmd_len))  /* compatibility */
 return ((char *) line);

    msg_warn("unsupported command in %s map: %s", map_class, cmd);
    return ((char *) line);
}

/* hbc_header_checks - process one complete header line */

char   *hbc_header_checks(void *context, HBC_CHECKS *hbc, int header_class,
             const HEADER_OPTS *hdr_opts,
             VSTRING *header, off_t offset)
{
    const char *myname = "hbc_header_checks";
    const char *action;
    HBC_MAP_INFO *mp;

    if (msg_verbose)
 msg_info("%s: '%.30s'", myname, STR(header));

    /*
     * XXX This is for compatibility with the cleanup(8) server.
     */

    if (hdr_opts && (hdr_opts->flags & HDR_OPT_MIME))
 header_class = MIME_HDR_MULTIPART;

    mp = hbc->map_info + HBC_HEADER_INDEX(header_class);

    if (mp->maps != 0 && (action = maps_find(mp->maps, STR(header), 0)) != 0) {
 return (hbc_action(context, hbc->call_backs,
      mp->map_class, HBC_CTXT_HEADER, action,
      STR(header), LEN(header), offset));
    } else if (mp->maps && mp->maps->error) {
 return (HBC_CHECKS_STAT_ERROR);
    } else {
 return (STR(header));
    }
}

/* hbc_body_checks - inspect one body record */

char   *hbc_body_checks(void *context, HBC_CHECKS *hbc, const char *line,
           ssize_t len, off_t offset)
{
    const char *myname = "hbc_body_checks";
    const char *action;
    HBC_MAP_INFO *mp;

    if (msg_verbose)
 msg_info("%s: '%.30s'", myname, line);

    mp = hbc->map_info;

    if ((action = maps_find(mp->maps, line, 0)) != 0) {
 return (hbc_action(context, hbc->call_backs,
      mp->map_class, HBC_CTXT_BODY, action,
      line, len, offset));
    } else if (mp->maps->error) {
 return (HBC_CHECKS_STAT_ERROR);
    } else {
 return ((char *) line);
    }
}

/* hbc_header_checks_create - create header checking context */

HBC_CHECKS *hbc_header_checks_create(const char *header_checks_name,
                 const char *header_checks_value,
            const char *mime_header_checks_name,
                  const char *mime_header_checks_value,
                 const char *nested_header_checks_name,
                const char *nested_header_checks_value,
                 HBC_CALL_BACKS *call_backs)
{
    HBC_CHECKS *hbc;

    /*
     * Optimize for the common case.
     */

    if (*header_checks_value == 0 && *mime_header_checks_value == 0
 && *nested_header_checks_value == 0) {
 return (0);
    } else {
 hbc = (HBC_CHECKS *) mymalloc(sizeof(*hbc)
   + (MIME_HDR_LAST - MIME_HDR_FIRST) * sizeof(HBC_MAP_INFO));
 hbc->call_backs = call_backs;
 HBC_INIT(hbc, HBC_HEADER_INDEX(MIME_HDR_PRIMARY),
   header_checks_name, header_checks_value);
 HBC_INIT(hbc, HBC_HEADER_INDEX(MIME_HDR_MULTIPART),
   mime_header_checks_name, mime_header_checks_value);
 HBC_INIT(hbc, HBC_HEADER_INDEX(MIME_HDR_NESTED),
   nested_header_checks_name, nested_header_checks_value);
 return (hbc);
    }
}

/* hbc_body_checks_create - create body checking context */

HBC_CHECKS *hbc_body_checks_create(const char *body_checks_name,
               const char *body_checks_value,
               HBC_CALL_BACKS *call_backs)
{
    HBC_CHECKS *hbc;

    /*
     * Optimize for the common case.
     */

    if (*body_checks_value == 0) {
 return (0);
    } else {
 hbc = (HBC_CHECKS *) mymalloc(sizeof(*hbc));
 hbc->call_backs = call_backs;
 HBC_INIT(hbc, HBC_BODY_INDEX, body_checks_name, body_checks_value);
 return (hbc);
    }
}

/* _hbc_checks_free - destroy header/body checking context */

void    _hbc_checks_free(HBC_CHECKS *hbc, ssize_t len)
{
    HBC_MAP_INFO *mp;

    for (mp = hbc->map_info; mp < hbc->map_info + len; mp++)
 if (mp->maps)
     maps_free(mp->maps);
    myfree((void *) hbc);
}

 /*
  * Test program. Specify the four maps on the command line, and feed a
  * MIME-formatted message on stdin.
  */


#ifdef TEST

#include <stdlib.h>
#include <stringops.h>
#include <vstream.h>
#include <msg_vstream.h>
#include <rec_streamlf.h>
#include <mail_params.h>

typedef struct {
    HBC_CHECKS *header_checks;
    HBC_CHECKS *body_checks;
    HBC_CALL_BACKS *call_backs;
    VSTREAM *fp;
    VSTRING *buf;
    const char *queueid;
    int     recno;
} HBC_TEST_CONTEXT;

/*#define REC_LEN 40*/
#define REC_LEN 1024

/* log_cb - log action with context */

static void log_cb(void *context, const char *action, const char *where,
             const char *content, const char *text)
{
    const HBC_TEST_CONTEXT *dp = (HBC_TEST_CONTEXT *) context;

    if (*text) {
 msg_info("%s: %s: %s %.200s: %s",
   dp->queueid, action, where, content, text);
    } else {
 msg_info("%s: %s: %s %.200s",
   dp->queueid, action, where, content);
    }
}

/* out_cb - output call-back */

static void out_cb(void *context, int rec_type, const char *buf,
             ssize_t len, off_t offset)
{
    const HBC_TEST_CONTEXT *dp = (HBC_TEST_CONTEXT *) context;

    vstream_fwrite(dp->fp, buf, len);
    VSTREAM_PUTC('\n', dp->fp);
    vstream_fflush(dp->fp);
}

/* head_out - MIME_STATE header call-back */

static void head_out(void *context, int header_class,
               const HEADER_OPTS *header_info,
               VSTRING *buf, off_t offset)
{
    HBC_TEST_CONTEXT *dp = (HBC_TEST_CONTEXT *) context;
    char   *out;

    if (dp->header_checks == 0
 || (out = hbc_header_checks(context, dp->header_checks, header_class,
        header_info, buf, offset)) == STR(buf)) {
 vstring_sprintf(dp->buf, "%d %s %ld\t|%s",
   dp->recno,
   header_class == MIME_HDR_PRIMARY ? "MAIN" :
   header_class == MIME_HDR_MULTIPART ? "MULT" :
   header_class == MIME_HDR_NESTED ? "NEST" :
   "ERROR", (long) offset, STR(buf));
 out_cb(dp, REC_TYPE_NORM, STR(dp->buf), LEN(dp->buf), offset);
    } else if (out != 0) {
 vstring_sprintf(dp->buf, "%d %s %ld\t|%s",
   dp->recno,
   header_class == MIME_HDR_PRIMARY ? "MAIN" :
   header_class == MIME_HDR_MULTIPART ? "MULT" :
   header_class == MIME_HDR_NESTED ? "NEST" :
   "ERROR", (long) offset, out);
 out_cb(dp, REC_TYPE_NORM, STR(dp->buf), LEN(dp->buf), offset);
 myfree(out);
    }
    dp->recno += 1;
}

/* header_end - MIME_STATE end-of-header call-back */

static void head_end(void *context)
{
    HBC_TEST_CONTEXT *dp = (HBC_TEST_CONTEXT *) context;

    out_cb(dp, 0"HEADER END"sizeof("HEADER END") - 10);
}

/* body_out - MIME_STATE body line call-back */

static void body_out(void *context, int rec_type, const char *buf,
               ssize_t len, off_t offset)
{
    HBC_TEST_CONTEXT *dp = (HBC_TEST_CONTEXT *) context;
    char   *out;

    if (dp->body_checks == 0
 || (out = hbc_body_checks(context, dp->body_checks,
      buf, len, offset)) == buf) {
 vstring_sprintf(dp->buf, "%d BODY %c %ld\t|%s",
   dp->recno, rec_type, (long) offset, buf);
 out_cb(dp, rec_type, STR(dp->buf), LEN(dp->buf), offset);
    } else if (out != 0) {
 vstring_sprintf(dp->buf, "%d BODY %c %ld\t|%s",
   dp->recno, rec_type, (long) offset, out);
 out_cb(dp, rec_type, STR(dp->buf), LEN(dp->buf), offset);
 myfree(out);
    }
    dp->recno += 1;
}

/* body_end - MIME_STATE end-of-message call-back */

static void body_end(void *context)
{
    HBC_TEST_CONTEXT *dp = (HBC_TEST_CONTEXT *) context;

    out_cb(dp, 0"BODY END"sizeof("BODY END") - 10);
}

/* err_print - print MIME_STATE errors */

static void err_print(void *unused_context, int err_flag,
                const char *text, ssize_t len)
{
    msg_warn("%s: %.*s", mime_state_error(err_flag),
      len < 100 ? (int) len : 100, text);
}

int     var_header_limit = 2000;
int     var_mime_maxdepth = 20;
int     var_mime_bound_len = 2000;
char   *var_drop_hdrs = DEF_DROP_HDRS;

int     main(int argc, char **argv)
{
    int     rec_type;
    VSTRING *buf;
    int     err;
    MIME_STATE *mime_state;
    HBC_TEST_CONTEXT context;
    static HBC_CALL_BACKS call_backs[1] = {
 log_cb,    /* logger */
 out_cb,    /* prepend */
    };

    /*
     * Sanity check.
     */

    if (argc != 5)
 msg_fatal("usage: %s header_checks mime_header_checks nested_header_checks body_checks", argv[0]);

    /*
     * Initialize.
     */

#define MIME_OPTIONS \
            (MIME_OPT_REPORT_8BIT_IN_7BIT_BODY \
            | MIME_OPT_REPORT_8BIT_IN_HEADER \
            | MIME_OPT_REPORT_ENCODING_DOMAIN \
            | MIME_OPT_REPORT_TRUNC_HEADER \
            | MIME_OPT_REPORT_NESTING \
            | MIME_OPT_DOWNGRADE)
    msg_vstream_init(basename(argv[0]), VSTREAM_OUT);
    buf = vstring_alloc(10);
    mime_state = mime_state_alloc(MIME_OPTIONS,
      head_out, head_end,
      body_out, body_end,
      err_print,
      (void *) &context);
    context.header_checks =
 hbc_header_checks_create("header_checks", argv[1],
     "mime_header_checks", argv[2],
     "nested_header_checks", argv[3],
     call_backs);
    context.body_checks =
 hbc_body_checks_create("body_checks", argv[4], call_backs);
    context.buf = vstring_alloc(100);
    context.fp = VSTREAM_OUT;
    context.queueid = "test-queueID";
    context.recno = 0;

    /*
     * Main loop.
     */

    do {
 rec_type = rec_streamlf_get(VSTREAM_IN, buf, REC_LEN);
 VSTRING_TERMINATE(buf);
 err = mime_state_update(mime_state, rec_type, STR(buf), LEN(buf));
 vstream_fflush(VSTREAM_OUT);
    } while (rec_type > 0);

    /*
     * Error reporting.
     */

    if (err & MIME_ERR_TRUNC_HEADER)
 msg_warn("message header length exceeds safety limit");
    if (err & MIME_ERR_NESTING)
 msg_warn("MIME nesting exceeds safety limit");
    if (err & MIME_ERR_8BIT_IN_HEADER)
 msg_warn("improper use of 8-bit data in message header");
    if (err & MIME_ERR_8BIT_IN_7BIT_BODY)
 msg_warn("improper use of 8-bit data in message body");
    if (err & MIME_ERR_ENCODING_DOMAIN)
 msg_warn("improper message/* or multipart/* encoding domain");

    /*
     * Cleanup.
     */

    if (context.header_checks)
 hbc_header_checks_free(context.header_checks);
    if (context.body_checks)
 hbc_body_checks_free(context.body_checks);
    vstring_free(context.buf);
    mime_state_free(mime_state);
    vstring_free(buf);
    exit(0);
}

#endif

Messung V0.5 in Prozent
C=75 H=95 G=85

¤ Dauer der Verarbeitung: 0.20 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