1 /* $NetBSD: smtp_key.c,v 1.2 2017/02/14 01:16:48 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 request nexthop destination. This is a proxy for 57 /* destination-dependent, but host-independent context. 58 /* .IP SMTP_KEY_FLAG_NEXTHOP 59 /* The current iterator's nexthop destination (request nexthop 60 /* or fallback nexthop, including optional [] and :port). This 61 /* is the form that users specify in a SASL or TLS lookup 62 /* tables. 63 /* .IP SMTP_KEY_FLAG_HOSTNAME 64 /* The current iterator's remote hostname. 65 /* .IP SMTP_KEY_FLAG_ADDR 66 /* The current iterator's remote address. 67 /* .IP SMTP_KEY_FLAG_PORT 68 /* The current iterator's remote port. 69 /* .RE 70 /* DIAGNOSTICS 71 /* Panic: undefined flag or zero flags. Fatal: out of memory. 72 /* LICENSE 73 /* .ad 74 /* .fi 75 /* The Secure Mailer license must be distributed with this software. 76 /* AUTHOR(S) 77 /* Wietse Venema 78 /* IBM T.J. Watson Research 79 /* P.O. Box 704 80 /* Yorktown Heights, NY 10598, USA 81 /*--*/ 82 83 /* 84 * System library. 85 */ 86 #include <sys_defs.h> 87 #include <netinet/in.h> /* ntohs() for Solaris or BSD */ 88 #include <arpa/inet.h> /* ntohs() for Linux or BSD */ 89 #include <string.h> 90 91 /* 92 * Utility library. 93 */ 94 #include <msg.h> 95 #include <vstring.h> 96 #include <base64_code.h> 97 98 /* 99 * Global library. 100 */ 101 #include <mail_params.h> 102 103 /* 104 * Application-specific. 105 */ 106 #include <smtp.h> 107 108 /* 109 * We use a configurable field terminator and optional place holder for data 110 * that is unavailable or inapplicable. We base64-encode content that 111 * contains these characters, and content that needs obfuscation. 112 */ 113 114 /* smtp_key_append_na - append place-holder key field */ 115 116 static void smtp_key_append_na(VSTRING *buffer, const char *delim_na) 117 { 118 if (delim_na[1] != 0) 119 VSTRING_ADDCH(buffer, delim_na[1]); 120 VSTRING_ADDCH(buffer, delim_na[0]); 121 } 122 123 /* smtp_key_append_str - append string-valued key field */ 124 125 static void smtp_key_append_str(VSTRING *buffer, const char *str, 126 const char *delim_na) 127 { 128 if (str == 0 || str[0] == 0) { 129 smtp_key_append_na(buffer, delim_na); 130 } else if (str[strcspn(str, delim_na)] != 0) { 131 base64_encode_opt(buffer, str, strlen(str), BASE64_FLAG_APPEND); 132 VSTRING_ADDCH(buffer, delim_na[0]); 133 } else { 134 vstring_sprintf_append(buffer, "%s%c", str, delim_na[0]); 135 } 136 } 137 138 /* smtp_key_append_uint - append unsigned-valued key field */ 139 140 static void smtp_key_append_uint(VSTRING *buffer, unsigned num, 141 const char *delim_na) 142 { 143 vstring_sprintf_append(buffer, "%u%c", num, delim_na[0]); 144 } 145 146 /* smtp_key_prefix - format common elements in lookup key */ 147 148 char *smtp_key_prefix(VSTRING *buffer, const char *delim_na, 149 SMTP_ITERATOR *iter, int flags) 150 { 151 static const char myname[] = "smtp_key_prefix"; 152 SMTP_STATE *state = iter->parent; /* private member */ 153 154 /* 155 * Sanity checks. 156 */ 157 if (state == 0) 158 msg_panic("%s: no parent state", myname); 159 if (flags & ~SMTP_KEY_MASK_ALL) 160 msg_panic("%s: unknown key flags 0x%x", 161 myname, flags & ~SMTP_KEY_MASK_ALL); 162 if (flags == 0) 163 msg_panic("%s: zero flags", myname); 164 165 /* 166 * Initialize. 167 */ 168 VSTRING_RESET(buffer); 169 170 /* 171 * Per-service and per-request context. 172 */ 173 if (flags & SMTP_KEY_FLAG_SERVICE) 174 smtp_key_append_str(buffer, state->service, delim_na); 175 if (flags & SMTP_KEY_FLAG_SENDER) 176 smtp_key_append_str(buffer, state->request->sender, delim_na); 177 178 /* 179 * Per-destination context, non-canonicalized form. 180 */ 181 if (flags & SMTP_KEY_FLAG_REQ_NEXTHOP) 182 smtp_key_append_str(buffer, STR(iter->request_nexthop), delim_na); 183 if (flags & SMTP_KEY_FLAG_NEXTHOP) 184 smtp_key_append_str(buffer, STR(iter->dest), delim_na); 185 186 /* 187 * Per-host context, canonicalized form. 188 */ 189 if (flags & SMTP_KEY_FLAG_HOSTNAME) 190 smtp_key_append_str(buffer, STR(iter->host), delim_na); 191 if (flags & SMTP_KEY_FLAG_ADDR) 192 smtp_key_append_str(buffer, STR(iter->addr), delim_na); 193 if (flags & SMTP_KEY_FLAG_PORT) 194 smtp_key_append_uint(buffer, ntohs(iter->port), delim_na); 195 196 /* Similarly, provide unique TLS fingerprint when applicable. */ 197 198 VSTRING_TERMINATE(buffer); 199 200 return STR(buffer); 201 } 202