xref: /netbsd-src/external/ibm-public/postfix/dist/src/smtp/smtp_key.c (revision 33881f779a77dce6440bdc44610d94de75bebefe)
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