1 /* $NetBSD: smtp_key.c,v 1.3 2020/03/18 19:05:20 christos Exp $ */ 2 3 /*++ 4 /* NAME 5 /* smtp_key 3 6 /* SUMMARY 7 /* cache/table lookup key management 8 /* SYNOPSIS 9 /* #include "smtp.h" 10 /* 11 /* char *smtp_key_prefix(buffer, delim_na, iterator, context_flags) 12 /* VSTRING *buffer; 13 /* const char *delim_na; 14 /* SMTP_ITERATOR *iterator; 15 /* int context_flags; 16 /* DESCRIPTION 17 /* The Postfix SMTP server accesses caches and lookup tables, 18 /* using lookup keys that contain information from various 19 /* contexts: per-server configuration, per-request envelope, 20 /* and results from DNS queries. 21 /* 22 /* These lookup keys sometimes share the same context information. 23 /* The primary purpose of this API is to ensure that this 24 /* shared context is used consistently, and that its use is 25 /* made explicit (both are needed to verify that there is no 26 /* false cache sharing). 27 /* 28 /* smtp_key_prefix() constructs a lookup key prefix from context 29 /* that may be shared with other lookup keys. The user is free 30 /* to append additional application-specific context. The result 31 /* value is a pointer to the result text. 32 /* 33 /* Arguments: 34 /* .IP buffer 35 /* Storage for the result. 36 /* .IP delim_na 37 /* The field delimiter character, and the optional place holder 38 /* character for a) information that is unavailable, b) 39 /* information that is inapplicable, or c) that would result 40 /* in an empty field. Key fields that contain "delim_na" 41 /* characters will be base64-encoded. 42 /* Do not specify "delim_na" characters that are part of the 43 /* base64 character set. 44 /* .IP iterator 45 /* Information that will be selected by the specified flags. 46 /* .IP context_flags 47 /* Bit-wise OR of one or more of the following. 48 /* .RS 49 /* .IP SMTP_KEY_FLAG_SERVICE 50 /* The global service name. This is a proxy for 51 /* destination-independent and request-independent context. 52 /* .IP SMTP_KEY_FLAG_SENDER 53 /* The envelope sender address. This is a proxy for sender-dependent 54 /* context, such as per-sender SASL authentication. 55 /* .IP SMTP_KEY_FLAG_REQ_NEXTHOP 56 /* The delivery request nexthop destination, including optional 57 /* [] and :port (the same form that users specify in a SASL 58 /* password or TLS policy lookup table). This is a proxy for 59 /* destination-dependent, but host-independent context. 60 /* .IP SMTP_KEY_FLAG_CUR_NEXTHOP 61 /* The current iterator's nexthop destination (delivery request 62 /* nexthop or fallback nexthop, including optional [] and 63 /* :port). 64 /* .IP SMTP_KEY_FLAG_HOSTNAME 65 /* The current iterator's remote hostname. 66 /* .IP SMTP_KEY_FLAG_ADDR 67 /* The current iterator's remote address. 68 /* .IP SMTP_KEY_FLAG_PORT 69 /* The current iterator's remote port. 70 /* .RE 71 /* DIAGNOSTICS 72 /* Panic: undefined flag or zero flags. Fatal: out of memory. 73 /* LICENSE 74 /* .ad 75 /* .fi 76 /* The Secure Mailer license must be distributed with this software. 77 /* AUTHOR(S) 78 /* Wietse Venema 79 /* IBM T.J. Watson Research 80 /* P.O. Box 704 81 /* Yorktown Heights, NY 10598, USA 82 /* 83 /* Wietse Venema 84 /* Google, Inc. 85 /* 111 8th Avenue 86 /* New York, NY 10011, USA 87 /*--*/ 88 89 /* 90 * System library. 91 */ 92 #include <sys_defs.h> 93 #include <netinet/in.h> /* ntohs() for Solaris or BSD */ 94 #include <arpa/inet.h> /* ntohs() for Linux or BSD */ 95 #include <string.h> 96 97 /* 98 * Utility library. 99 */ 100 #include <msg.h> 101 #include <vstring.h> 102 #include <base64_code.h> 103 104 /* 105 * Global library. 106 */ 107 #include <mail_params.h> 108 109 /* 110 * Application-specific. 111 */ 112 #include <smtp.h> 113 114 /* 115 * We use a configurable field terminator and optional place holder for data 116 * that is unavailable or inapplicable. We base64-encode content that 117 * contains these characters, and content that needs obfuscation. 118 */ 119 120 /* smtp_key_append_na - append place-holder key field */ 121 122 static void smtp_key_append_na(VSTRING *buffer, const char *delim_na) 123 { 124 if (delim_na[1] != 0) 125 VSTRING_ADDCH(buffer, delim_na[1]); 126 VSTRING_ADDCH(buffer, delim_na[0]); 127 } 128 129 /* smtp_key_append_str - append string-valued key field */ 130 131 static void smtp_key_append_str(VSTRING *buffer, const char *str, 132 const char *delim_na) 133 { 134 if (str == 0 || str[0] == 0) { 135 smtp_key_append_na(buffer, delim_na); 136 } else if (str[strcspn(str, delim_na)] != 0) { 137 base64_encode_opt(buffer, str, strlen(str), BASE64_FLAG_APPEND); 138 VSTRING_ADDCH(buffer, delim_na[0]); 139 } else { 140 vstring_sprintf_append(buffer, "%s%c", str, delim_na[0]); 141 } 142 } 143 144 /* smtp_key_append_uint - append unsigned-valued key field */ 145 146 static void smtp_key_append_uint(VSTRING *buffer, unsigned num, 147 const char *delim_na) 148 { 149 vstring_sprintf_append(buffer, "%u%c", num, delim_na[0]); 150 } 151 152 /* smtp_key_prefix - format common elements in lookup key */ 153 154 char *smtp_key_prefix(VSTRING *buffer, const char *delim_na, 155 SMTP_ITERATOR *iter, int flags) 156 { 157 static const char myname[] = "smtp_key_prefix"; 158 SMTP_STATE *state = iter->parent; /* private member */ 159 160 /* 161 * Sanity checks. 162 */ 163 if (state == 0) 164 msg_panic("%s: no parent state", myname); 165 if (flags & ~SMTP_KEY_MASK_ALL) 166 msg_panic("%s: unknown key flags 0x%x", 167 myname, flags & ~SMTP_KEY_MASK_ALL); 168 if (flags == 0) 169 msg_panic("%s: zero flags", myname); 170 171 /* 172 * Initialize. 173 */ 174 VSTRING_RESET(buffer); 175 176 /* 177 * Per-service and per-request context. 178 */ 179 if (flags & SMTP_KEY_FLAG_SERVICE) 180 smtp_key_append_str(buffer, state->service, delim_na); 181 if (flags & SMTP_KEY_FLAG_SENDER) 182 smtp_key_append_str(buffer, state->request->sender, delim_na); 183 184 /* 185 * Per-destination context, non-canonicalized form. 186 */ 187 if (flags & SMTP_KEY_FLAG_REQ_NEXTHOP) 188 smtp_key_append_str(buffer, STR(iter->request_nexthop), delim_na); 189 if (flags & SMTP_KEY_FLAG_CUR_NEXTHOP) 190 smtp_key_append_str(buffer, STR(iter->dest), delim_na); 191 192 /* 193 * Per-host context, canonicalized form. 194 */ 195 if (flags & SMTP_KEY_FLAG_HOSTNAME) 196 smtp_key_append_str(buffer, STR(iter->host), delim_na); 197 if (flags & SMTP_KEY_FLAG_ADDR) 198 smtp_key_append_str(buffer, STR(iter->addr), delim_na); 199 if (flags & SMTP_KEY_FLAG_PORT) 200 smtp_key_append_uint(buffer, ntohs(iter->port), delim_na); 201 202 /* 203 * Requested TLS level, if applicable. TODO(tlsproxy) should the lookup 204 * engine also try the requested TLS level and 'stronger', in case a 205 * server hosts multiple domains with different TLS requirements? 206 */ 207 if (flags & SMTP_KEY_FLAG_TLS_LEVEL) 208 #ifdef USE_TLS 209 smtp_key_append_uint(buffer, state->tls->level, delim_na); 210 #else 211 smtp_key_append_na(buffer, delim_na); 212 #endif 213 214 VSTRING_TERMINATE(buffer); 215 216 return STR(buffer); 217 } 218