xref: /netbsd-src/external/ibm-public/postfix/dist/src/smtpd/smtpd_expand.c (revision e89934bbf778a6d6d6894877c4da59d0c7835b0f)
1 /*	$NetBSD: smtpd_expand.c,v 1.2 2017/02/14 01:16:48 christos Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	smtpd_expand 3
6 /* SUMMARY
7 /*	SMTP server macro expansion
8 /* SYNOPSIS
9 /*	#include <smtpd.h>
10 /*	#include <smtpd_expand.h>
11 /*
12 /*	void	smtpd_expand_init()
13 /*
14 /*	int	smtpd_expand(state, result, template, flags)
15 /*	SMTPD_STATE *state;
16 /*	VSTRING	*result;
17 /*	const char *template;
18 /*	int	flags;
19 /* LOW_LEVEL INTERFACE
20 /*	VSTRING *smtpd_expand_filter;
21 /*
22 /*	const char *smtpd_expand_lookup(name, unused_mode, context)
23 /*	const char *name;
24 /*	int	unused_mode;
25 /*	void	*context;
26 /*	const char *template;
27 /* DESCRIPTION
28 /*	This module expands session-related macros.
29 /*
30 /*	smtpd_expand_init() performs one-time initialization.
31 /*
32 /*	smtpd_expand() expands macros in the template, using session
33 /*	attributes in the state argument, and writes the result to
34 /*	the result argument. The flags and result value are as with
35 /*	mac_expand().
36 /*
37 /*	smtpd_expand_filter and smtpd_expand_lookup() provide access
38 /*	to lower-level interfaces that are used by smtpd_expand().
39 /*	smtpd_expand_lookup() returns null when a string is not
40 /*	found (or when it is a null pointer).
41 /* DIAGNOSTICS
42 /*	Panic: interface violations. Fatal errors: out of memory.
43 /*	internal protocol errors. smtpd_expand() returns the binary
44 /*	OR of MAC_PARSE_ERROR (syntax error) and MAC_PARSE_UNDEF
45 /*	(undefined macro name).
46 /* LICENSE
47 /* .ad
48 /* .fi
49 /*	The Secure Mailer license must be distributed with this software.
50 /* AUTHOR(S)
51 /*	Wietse Venema
52 /*	IBM T.J. Watson Research
53 /*	P.O. Box 704
54 /*	Yorktown Heights, NY 10598, USA
55 /*--*/
56 
57 /* System library. */
58 
59 #include <sys_defs.h>
60 #include <time.h>
61 
62 /* Utility library. */
63 
64 #include <msg.h>
65 #include <vstring.h>
66 #include <mac_expand.h>
67 #include <stringops.h>
68 
69 /* Global library. */
70 
71 #include <mail_params.h>
72 #include <mail_proto.h>
73 
74 /* Application-specific. */
75 
76 #include <smtpd.h>
77 #include <smtpd_expand.h>
78 
79  /*
80   * Pre-parsed expansion filter.
81   */
82 VSTRING *smtpd_expand_filter;
83 
84  /*
85   * SLMs.
86   */
87 #define STR	vstring_str
88 
89 /* smtpd_expand_init - initialize once during process lifetime */
90 
smtpd_expand_init(void)91 void    smtpd_expand_init(void)
92 {
93 
94     /*
95      * Expand the expansion filter :-)
96      */
97     smtpd_expand_filter = vstring_alloc(10);
98     unescape(smtpd_expand_filter, var_smtpd_exp_filter);
99 }
100 
101 /* smtpd_expand_unknown - report unknown macro name */
102 
smtpd_expand_unknown(const char * name)103 static void smtpd_expand_unknown(const char *name)
104 {
105     msg_warn("unknown macro name \"%s\" in expansion request", name);
106 }
107 
108 /* smtpd_expand_addr - return address or substring thereof */
109 
smtpd_expand_addr(VSTRING * buf,const char * addr,const char * name,int prefix_len)110 static const char *smtpd_expand_addr(VSTRING *buf, const char *addr,
111 				           const char *name, int prefix_len)
112 {
113     const char *p;
114     const char *suffix;
115 
116     /*
117      * Return NULL only for unknown names in expansion requests.
118      */
119     if (addr == 0)
120 	return ("");
121 
122     suffix = name + prefix_len;
123 
124     /*
125      * MAIL_ATTR_SENDER or MAIL_ATTR_RECIP.
126      */
127     if (*suffix == 0) {
128 	if (*addr)
129 	    return (addr);
130 	else
131 	    return ("<>");
132     }
133 
134     /*
135      * "sender_name" or "recipient_name".
136      */
137 #define STREQ(x,y) (*(x) == *(y) && strcmp((x), (y)) == 0)
138 
139     else if (STREQ(suffix, MAIL_ATTR_S_NAME)) {
140 	if (*addr) {
141 	    if ((p = strrchr(addr, '@')) != 0) {
142 		vstring_strncpy(buf, addr, p - addr);
143 		return (STR(buf));
144 	    } else {
145 		return (addr);
146 	    }
147 	} else
148 	    return ("<>");
149     }
150 
151     /*
152      * "sender_domain" or "recipient_domain".
153      */
154     else if (STREQ(suffix, MAIL_ATTR_S_DOMAIN)) {
155 	if (*addr) {
156 	    if ((p = strrchr(addr, '@')) != 0) {
157 		return (p + 1);
158 	    } else {
159 		return ("");
160 	    }
161 	} else
162 	    return ("");
163     }
164 
165     /*
166      * Unknown. Return NULL to indicate an "unknown name" error.
167      */
168     else {
169 	smtpd_expand_unknown(name);
170 	return (0);
171     }
172 }
173 
174 /* smtpd_expand_lookup - generic SMTP attribute $name expansion */
175 
smtpd_expand_lookup(const char * name,int unused_mode,void * context)176 const char *smtpd_expand_lookup(const char *name, int unused_mode,
177 				        void *context)
178 {
179     SMTPD_STATE *state = (SMTPD_STATE *) context;
180     time_t  now;
181     struct tm *lt;
182 
183     if (state->expand_buf == 0)
184 	state->expand_buf = vstring_alloc(10);
185 
186     if (msg_verbose > 1)
187 	msg_info("smtpd_expand_lookup: ${%s}", name);
188 
189 #define STREQN(x,y,n) (*(x) == *(y) && strncmp((x), (y), (n)) == 0)
190 #define CONST_LEN(x)  (sizeof(x) - 1)
191 
192     /*
193      * Don't query main.cf parameters, as the result of expansion could
194      * reveal system-internal information in server replies.
195      *
196      * XXX: This said, multiple servers may be behind a single client-visible
197      * name or IP address, and each may generate its own logs. Therefore, it
198      * may be useful to expose the replying MTA id (myhostname) in the
199      * contact footer, to identify the right logs. So while we don't expose
200      * the raw configuration dictionary, we do expose "$myhostname" as
201      * expanded in var_myhostname.
202      *
203      * Return NULL only for non-existent names.
204      */
205     if (STREQ(name, MAIL_ATTR_SERVER_NAME)) {
206 	return (var_myhostname);
207     } else if (STREQ(name, MAIL_ATTR_ACT_CLIENT)) {
208 	return (state->namaddr);
209     } else if (STREQ(name, MAIL_ATTR_ACT_CLIENT_PORT)) {
210 	return (state->port);
211     } else if (STREQ(name, MAIL_ATTR_ACT_CLIENT_ADDR)) {
212 	return (state->addr);
213     } else if (STREQ(name, MAIL_ATTR_ACT_CLIENT_NAME)) {
214 	return (state->name);
215     } else if (STREQ(name, MAIL_ATTR_ACT_REVERSE_CLIENT_NAME)) {
216 	return (state->reverse_name);
217     } else if (STREQ(name, MAIL_ATTR_ACT_HELO_NAME)) {
218 	return (state->helo_name ? state->helo_name : "");
219     } else if (STREQN(name, MAIL_ATTR_SENDER, CONST_LEN(MAIL_ATTR_SENDER))) {
220 	return (smtpd_expand_addr(state->expand_buf, state->sender,
221 				  name, CONST_LEN(MAIL_ATTR_SENDER)));
222     } else if (STREQN(name, MAIL_ATTR_RECIP, CONST_LEN(MAIL_ATTR_RECIP))) {
223 	return (smtpd_expand_addr(state->expand_buf, state->recipient,
224 				  name, CONST_LEN(MAIL_ATTR_RECIP)));
225     } if (STREQ(name, MAIL_ATTR_LOCALTIME)) {
226 	if (time(&now) == (time_t) -1)
227 	    msg_fatal("time lookup failed: %m");
228 	lt = localtime(&now);
229 	VSTRING_RESET(state->expand_buf);
230 	do {
231 	    VSTRING_SPACE(state->expand_buf, 100);
232 	} while (strftime(STR(state->expand_buf),
233 			  vstring_avail(state->expand_buf),
234 			  "%b %d %H:%M:%S", lt) == 0);
235 	return (STR(state->expand_buf));
236     } else {
237 	smtpd_expand_unknown(name);
238 	return (0);
239     }
240 }
241 
242 /* smtpd_expand - expand session attributes in string */
243 
smtpd_expand(SMTPD_STATE * state,VSTRING * result,const char * template,int flags)244 int     smtpd_expand(SMTPD_STATE *state, VSTRING *result,
245 		             const char *template, int flags)
246 {
247     return (mac_expand(result, template, flags, STR(smtpd_expand_filter),
248 		       smtpd_expand_lookup, (void *) state));
249 }
250