Home | History | Annotate | Line # | Download | only in global
      1 /*	$NetBSD: header_opts.c,v 1.4 2026/05/09 18:49:16 christos Exp $	*/
      2 
      3 /*++
      4 /* NAME
      5 /*	header_opts 3
      6 /* SUMMARY
      7 /*	message header classification
      8 /* SYNOPSIS
      9 /*	#include <header_opts.h>
     10 /*
     11 /*	const HEADER_OPTS *header_opts_find(string)
     12 /*	const char *string;
     13 /* DESCRIPTION
     14 /*	header_opts_find() takes a message header line and looks up control
     15 /*	information for the corresponding header type.
     16 /* DIAGNOSTICS
     17 /*	Panic: input is not a valid header line. The result is a pointer
     18 /*	to HEADER_OPTS in case of success, a null pointer when the header
     19 /*	label was not recognized.
     20 /* SEE ALSO
     21 /*	header_opts(3h) the gory details
     22 /* LICENSE
     23 /* .ad
     24 /* .fi
     25 /*	The Secure Mailer license must be distributed with this software.
     26 /* AUTHOR(S)
     27 /*	Wietse Venema
     28 /*	IBM T.J. Watson Research
     29 /*	P.O. Box 704
     30 /*	Yorktown Heights, NY 10598, USA
     31 /*
     32 /*	Wietse Venema
     33 /*	porcupine.org
     34 /*--*/
     35 
     36 /* System library. */
     37 
     38 #include <sys_defs.h>
     39 #include <ctype.h>
     40 
     41 /* Utility library. */
     42 
     43 #include <msg.h>
     44 #include <htable.h>
     45 #include <vstring.h>
     46 #include <stringops.h>
     47 #include <argv.h>
     48 #include <mymalloc.h>
     49 
     50 /* Global library. */
     51 
     52 #include <mail_params.h>
     53 #include <header_opts.h>
     54 
     55  /*
     56   * Header names are given in the preferred capitalization. The lookups are
     57   * case-insensitive.
     58   *
     59   * XXX Removing Return-Path: headers should probably be done only with mail
     60   * that enters via a non-SMTP channel. Changing this now could break other
     61   * software. See also comments in bounce_notify_util.c.
     62   */
     63 static HEADER_OPTS header_opts[] = {
     64     "Apparently-To", HDR_APPARENTLY_TO, HDR_OPT_RECIP,
     65     "Bcc", HDR_BCC, HDR_OPT_XRECIP,
     66     "Cc", HDR_CC, HDR_OPT_XRECIP,
     67     "Content-Description", HDR_CONTENT_DESCRIPTION, HDR_OPT_MIME,
     68     "Content-Disposition", HDR_CONTENT_DISPOSITION, HDR_OPT_MIME,
     69     "Content-ID", HDR_CONTENT_ID, HDR_OPT_MIME,
     70     "Content-Length", HDR_CONTENT_LENGTH, 0,
     71     "Content-Transfer-Encoding", HDR_CONTENT_TRANSFER_ENCODING, HDR_OPT_MIME,
     72     "Content-Type", HDR_CONTENT_TYPE, HDR_OPT_MIME,
     73     "Delivered-To", HDR_DELIVERED_TO, 0,
     74     "Disposition-Notification-To", HDR_DISP_NOTIFICATION, HDR_OPT_SENDER,
     75     "Date", HDR_DATE, 0,
     76     "Errors-To", HDR_ERRORS_TO, HDR_OPT_SENDER,
     77     "From", HDR_FROM, HDR_OPT_SENDER,
     78     "Mail-Followup-To", HDR_MAIL_FOLLOWUP_TO, HDR_OPT_SENDER,
     79     "Message-Id", HDR_MESSAGE_ID, 0,
     80     "MIME-Version", HDR_MIME_VERSION, HDR_OPT_MIME,
     81     "Received", HDR_RECEIVED, 0,
     82     "Reply-To", HDR_REPLY_TO, HDR_OPT_SENDER,
     83     "Resent-Bcc", HDR_RESENT_BCC, HDR_OPT_XRECIP | HDR_OPT_RR,
     84     "Resent-Cc", HDR_RESENT_CC, HDR_OPT_XRECIP | HDR_OPT_RR,
     85     "Resent-Date", HDR_RESENT_DATE, HDR_OPT_RR,
     86     "Resent-From", HDR_RESENT_FROM, HDR_OPT_SENDER | HDR_OPT_RR,
     87     "Resent-Message-Id", HDR_RESENT_MESSAGE_ID, HDR_OPT_RR,
     88     "Resent-Reply-To", HDR_RESENT_REPLY_TO, HDR_OPT_RECIP | HDR_OPT_RR,
     89     "Resent-Sender", HDR_RESENT_SENDER, HDR_OPT_SENDER | HDR_OPT_RR,
     90     "Resent-To", HDR_RESENT_TO, HDR_OPT_XRECIP | HDR_OPT_RR,
     91     "Return-Path", HDR_RETURN_PATH, HDR_OPT_SENDER,
     92     "Return-Receipt-To", HDR_RETURN_RECEIPT_TO, HDR_OPT_SENDER,
     93     "Sender", HDR_SENDER, HDR_OPT_SENDER,
     94     "To", HDR_TO, HDR_OPT_XRECIP,
     95     "TLS-Required", HDR_TLS_REQUIRED, 0,
     96     "Require-TLS-ESMTP", HDR_REQTLS_ESMTP, 0,
     97 };
     98 
     99 #define HEADER_OPTS_SIZE (sizeof(header_opts) / sizeof(header_opts[0]))
    100 
    101 static HTABLE *header_hash;		/* quick lookup */
    102 static VSTRING *header_key;
    103 
    104 /* header_opts_init - initialize */
    105 
    106 static void header_opts_init(void)
    107 {
    108     const HEADER_OPTS *hp;
    109     const char *cp;
    110 
    111     /*
    112      * Build a hash table for quick lookup, and allocate memory for
    113      * lower-casing the lookup key.
    114      */
    115     header_key = vstring_alloc(10);
    116     header_hash = htable_create(HEADER_OPTS_SIZE);
    117     for (hp = header_opts; hp < header_opts + HEADER_OPTS_SIZE; hp++) {
    118 	VSTRING_RESET(header_key);
    119 	for (cp = hp->name; *cp; cp++)
    120 	    VSTRING_ADDCH(header_key, TOLOWER(*cp));
    121 	VSTRING_TERMINATE(header_key);
    122 	htable_enter(header_hash, vstring_str(header_key), (void *) hp);
    123     }
    124 }
    125 
    126 /* header_drop_init - initialize "header drop" flags */
    127 
    128 static void header_drop_init(void)
    129 {
    130     ARGV   *hdr_drop_list;
    131     char  **cpp;
    132     HTABLE_INFO *ht;
    133     HEADER_OPTS *hp;
    134 
    135     /*
    136      * Having one main.cf parameter for the "drop" header flag does not
    137      * generalize to the "sender", "extract", etc., flags. Flags would need
    138      * to be grouped by header name, but that would be unwieldy, too:
    139      *
    140      * message_header_flags = { apparently-to = recipient }, { bcc = recipient,
    141      * extract, drop }, { from = sender }, ...
    142      *
    143      * Thus, it is unlikely that all header flags will become configurable.
    144      */
    145     hdr_drop_list = argv_split(var_drop_hdrs, CHARS_COMMA_SP);
    146     for (cpp = hdr_drop_list->argv; *cpp; cpp++) {
    147 	lowercase(*cpp);
    148 	if ((ht = htable_locate(header_hash, *cpp)) == 0) {
    149 	    hp = (HEADER_OPTS *) mymalloc(sizeof(*hp));
    150 	    hp->type = HDR_OTHER;
    151 	    hp->flags = HDR_OPT_DROP;
    152 	    ht = htable_enter(header_hash, *cpp, (void *) hp);
    153 	    hp->name = ht->key;
    154 	} else
    155 	    hp = (HEADER_OPTS *) ht->value;
    156 	hp->flags |= HDR_OPT_DROP;
    157     }
    158     argv_free(hdr_drop_list);
    159 }
    160 
    161 /* header_opts_find - look up header options */
    162 
    163 const HEADER_OPTS *header_opts_find(const char *string)
    164 {
    165     const char *cp;
    166 
    167     if (header_hash == 0) {
    168 	header_opts_init();
    169 	header_drop_init();
    170     }
    171 
    172     /*
    173      * Look up the lower-cased version of the header name.
    174      */
    175     VSTRING_RESET(header_key);
    176     for (cp = string; *cp != ':'; cp++) {
    177 	if (*cp == 0)
    178 	    msg_panic("header_opts_find: no colon in header: %.30s", string);
    179 	VSTRING_ADDCH(header_key, TOLOWER(*cp));
    180     }
    181     vstring_truncate(header_key,
    182 		     trimblanks(vstring_str(header_key), cp - string)
    183 		     - vstring_str(header_key));
    184     VSTRING_TERMINATE(header_key);
    185     return ((const HEADER_OPTS *) htable_find(header_hash, vstring_str(header_key)));
    186 }
    187