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