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