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