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
smtp_key_append_na(VSTRING * buffer,const char * delim_na)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
smtp_key_append_str(VSTRING * buffer,const char * str,const char * delim_na)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
smtp_key_append_uint(VSTRING * buffer,unsigned num,const char * delim_na)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
smtp_key_prefix(VSTRING * buffer,const char * delim_na,SMTP_ITERATOR * iter,int flags)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