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