1 /* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
2
3 #include "lib.h"
4 #include "llist.h"
5 #include "str-sanitize.h"
6 #include "smtp-address.h"
7 #include "smtp-reply.h"
8
9 #include "smtp-server-private.h"
10
11 static void
smtp_server_recipient_update_event(struct smtp_server_recipient_private * prcpt)12 smtp_server_recipient_update_event(struct smtp_server_recipient_private *prcpt)
13 {
14 struct event *event = prcpt->rcpt.event;
15 const char *path = smtp_address_encode(prcpt->rcpt.path);
16
17 event_add_str(event, "rcpt_to", path);
18 smtp_params_rcpt_add_to_event(&prcpt->rcpt.params, event);
19 event_set_append_log_prefix(
20 event, t_strdup_printf("rcpt %s: ", str_sanitize(path, 128)));
21 }
22
23 static void
smtp_server_recipient_create_event(struct smtp_server_recipient_private * prcpt)24 smtp_server_recipient_create_event(struct smtp_server_recipient_private *prcpt)
25 {
26 struct smtp_server_recipient *rcpt = &prcpt->rcpt;
27 struct smtp_server_connection *conn = rcpt->conn;
28
29 if (rcpt->event != NULL)
30 return;
31
32 if (conn->state.trans == NULL) {
33 /* Create event for the transaction early. */
34 if (conn->next_trans_event == NULL) {
35 conn->next_trans_event = event_create(conn->event);
36 event_set_append_log_prefix(conn->next_trans_event,
37 "trans: ");
38 }
39 rcpt->event = event_create(conn->next_trans_event);
40 } else {
41 /* Use existing transaction event. */
42 rcpt->event = event_create(conn->state.trans->event);
43 }
44 /* Drop transaction log prefix so that the connection event prefix
45 remains. */
46 event_drop_parent_log_prefixes(rcpt->event, 1);
47
48 smtp_server_recipient_update_event(prcpt);
49 }
50
51 struct smtp_server_recipient *
smtp_server_recipient_create(struct smtp_server_cmd_ctx * cmd,const struct smtp_address * rcpt_to,const struct smtp_params_rcpt * params)52 smtp_server_recipient_create(struct smtp_server_cmd_ctx *cmd,
53 const struct smtp_address *rcpt_to,
54 const struct smtp_params_rcpt *params)
55 {
56 struct smtp_server_recipient_private *prcpt;
57 pool_t pool;
58
59 pool = pool_alloconly_create("smtp server recipient", 512);
60 prcpt = p_new(pool, struct smtp_server_recipient_private, 1);
61 prcpt->refcount = 1;
62 prcpt->rcpt.pool = pool;
63 prcpt->rcpt.conn = cmd->conn;
64 prcpt->rcpt.cmd = cmd;
65 prcpt->rcpt.path = smtp_address_clone(pool, rcpt_to);
66 smtp_params_rcpt_copy(pool, &prcpt->rcpt.params, params);
67
68 smtp_server_recipient_create_event(prcpt);
69
70 return &prcpt->rcpt;
71 }
72
smtp_server_recipient_ref(struct smtp_server_recipient * rcpt)73 void smtp_server_recipient_ref(struct smtp_server_recipient *rcpt)
74 {
75 struct smtp_server_recipient_private *prcpt =
76 (struct smtp_server_recipient_private *)rcpt;
77
78 if (prcpt->destroying)
79 return;
80 i_assert(prcpt->refcount > 0);
81 prcpt->refcount++;
82 }
83
smtp_server_recipient_unref(struct smtp_server_recipient ** _rcpt)84 bool smtp_server_recipient_unref(struct smtp_server_recipient **_rcpt)
85 {
86 struct smtp_server_recipient *rcpt = *_rcpt;
87 struct smtp_server_recipient_private *prcpt =
88 (struct smtp_server_recipient_private *)rcpt;
89
90 *_rcpt = NULL;
91
92 if (rcpt == NULL)
93 return FALSE;
94 if (prcpt->destroying)
95 return FALSE;
96
97 i_assert(prcpt->refcount > 0);
98 if (--prcpt->refcount > 0)
99 return TRUE;
100 prcpt->destroying = TRUE;
101
102 if (!smtp_server_recipient_call_hooks(
103 &rcpt, SMTP_SERVER_RECIPIENT_HOOK_DESTROY))
104 i_unreached();
105
106 if (!rcpt->finished) {
107 smtp_server_recipient_create_event(prcpt);
108
109 struct event_passthrough *e =
110 event_create_passthrough(rcpt->event)->
111 set_name("smtp_server_transaction_rcpt_finished");
112 e->add_int("status_code", 9000);
113 e->add_str("enhanced_code", "9.0.0");
114 e->add_str("error", "Aborted");
115
116 e_debug(e->event(), "Aborted");
117 }
118
119 event_unref(&rcpt->event);
120 pool_unref(&rcpt->pool);
121 return FALSE;
122 }
123
smtp_server_recipient_destroy(struct smtp_server_recipient ** _rcpt)124 void smtp_server_recipient_destroy(struct smtp_server_recipient **_rcpt)
125 {
126 smtp_server_recipient_unref(_rcpt);
127 }
128
129 const struct smtp_address *
smtp_server_recipient_get_original(struct smtp_server_recipient * rcpt)130 smtp_server_recipient_get_original(struct smtp_server_recipient *rcpt)
131 {
132 if (rcpt->params.orcpt.addr == NULL)
133 return rcpt->path;
134 return rcpt->params.orcpt.addr;
135 }
136
smtp_server_recipient_approved(struct smtp_server_recipient ** _rcpt)137 bool smtp_server_recipient_approved(struct smtp_server_recipient **_rcpt)
138 {
139 struct smtp_server_recipient *rcpt = *_rcpt;
140 struct smtp_server_transaction *trans = rcpt->conn->state.trans;
141
142 i_assert(trans != NULL);
143 i_assert(rcpt->event != NULL);
144
145 e_debug(rcpt->event, "Approved");
146
147 rcpt->cmd = NULL;
148 smtp_server_transaction_add_rcpt(trans, rcpt);
149
150 return smtp_server_recipient_call_hooks(
151 _rcpt, SMTP_SERVER_RECIPIENT_HOOK_APPROVED);
152 }
153
smtp_server_recipient_denied(struct smtp_server_recipient * rcpt,const struct smtp_server_reply * reply)154 void smtp_server_recipient_denied(struct smtp_server_recipient *rcpt,
155 const struct smtp_server_reply *reply)
156 {
157 i_assert(!rcpt->finished);
158 i_assert(rcpt->event != NULL);
159
160 rcpt->finished = TRUE;
161
162 struct event_passthrough *e =
163 event_create_passthrough(rcpt->event)->
164 set_name("smtp_server_transaction_rcpt_finished");
165 smtp_server_reply_add_to_event(reply, e);
166
167 e_debug(e->event(), "Denied");
168 }
169
smtp_server_recipient_data_command(struct smtp_server_recipient * rcpt,struct smtp_server_cmd_ctx * cmd)170 void smtp_server_recipient_data_command(struct smtp_server_recipient *rcpt,
171 struct smtp_server_cmd_ctx *cmd)
172 {
173 rcpt->cmd = cmd;
174 }
175
smtp_server_recipient_data_replied(struct smtp_server_recipient * rcpt)176 void smtp_server_recipient_data_replied(struct smtp_server_recipient *rcpt)
177 {
178 if (rcpt->replied)
179 return;
180 if (smtp_server_recipient_get_reply(rcpt) == NULL)
181 return;
182 rcpt->replied = TRUE;
183 if (!smtp_server_recipient_call_hooks(
184 &rcpt, SMTP_SERVER_RECIPIENT_HOOK_DATA_REPLIED)) {
185 /* Nothing to do */
186 }
187 }
188
189 struct smtp_server_reply *
smtp_server_recipient_get_reply(struct smtp_server_recipient * rcpt)190 smtp_server_recipient_get_reply(struct smtp_server_recipient *rcpt)
191 {
192 if (!HAS_ALL_BITS(rcpt->trans->flags,
193 SMTP_SERVER_TRANSACTION_FLAG_REPLY_PER_RCPT))
194 return smtp_server_command_get_reply(rcpt->cmd->cmd, 0);
195 return smtp_server_command_get_reply(rcpt->cmd->cmd, rcpt->index);
196 }
197
smtp_server_recipient_is_replied(struct smtp_server_recipient * rcpt)198 bool smtp_server_recipient_is_replied(struct smtp_server_recipient *rcpt)
199 {
200 i_assert(rcpt->cmd != NULL);
201
202 return smtp_server_command_is_replied(rcpt->cmd->cmd);
203 }
204
smtp_server_recipient_replyv(struct smtp_server_recipient * rcpt,unsigned int status,const char * enh_code,const char * fmt,va_list args)205 void smtp_server_recipient_replyv(struct smtp_server_recipient *rcpt,
206 unsigned int status, const char *enh_code,
207 const char *fmt, va_list args)
208 {
209 i_assert(rcpt->cmd != NULL);
210
211 if (smtp_server_command_is_rcpt(rcpt->cmd) && (status / 100) == 2) {
212 smtp_server_reply_indexv(rcpt->cmd, rcpt->index,
213 status, enh_code, fmt, args);
214 return;
215 }
216
217 smtp_server_reply_index(rcpt->cmd, rcpt->index, status, enh_code,
218 "<%s> %s", smtp_address_encode(rcpt->path),
219 t_strdup_vprintf(fmt, args));
220 }
221
smtp_server_recipient_reply(struct smtp_server_recipient * rcpt,unsigned int status,const char * enh_code,const char * fmt,...)222 void smtp_server_recipient_reply(struct smtp_server_recipient *rcpt,
223 unsigned int status, const char *enh_code,
224 const char *fmt, ...)
225 {
226 va_list args;
227
228 va_start(args, fmt);
229 smtp_server_recipient_replyv(rcpt, status, enh_code, fmt, args);
230 va_end(args);
231 }
232
smtp_server_recipient_reply_forward(struct smtp_server_recipient * rcpt,const struct smtp_reply * from)233 void smtp_server_recipient_reply_forward(struct smtp_server_recipient *rcpt,
234 const struct smtp_reply *from)
235 {
236 bool add_path = (!smtp_server_command_is_rcpt(rcpt->cmd) ||
237 !smtp_reply_is_success(from));
238 struct smtp_server_reply *reply;
239
240 reply = smtp_server_reply_create_forward(rcpt->cmd->cmd, rcpt->index,
241 from);
242 smtp_server_reply_replace_path(reply, rcpt->path, add_path);
243 smtp_server_reply_submit(reply);
244 }
245
smtp_server_recipient_reset(struct smtp_server_recipient * rcpt)246 void smtp_server_recipient_reset(struct smtp_server_recipient *rcpt)
247 {
248 i_assert(!rcpt->finished);
249 rcpt->finished = TRUE;
250
251 struct event_passthrough *e =
252 event_create_passthrough(rcpt->event)->
253 set_name("smtp_server_transaction_rcpt_finished");
254 e->add_int("status_code", 9000);
255 e->add_str("enhanced_code", "9.0.0");
256 e->add_str("error", "Reset");
257
258 e_debug(e->event(), "Reset");
259 }
260
smtp_server_recipient_finished(struct smtp_server_recipient * rcpt,const struct smtp_server_reply * reply)261 void smtp_server_recipient_finished(struct smtp_server_recipient *rcpt,
262 const struct smtp_server_reply *reply)
263 {
264 i_assert(!rcpt->finished);
265 rcpt->finished = TRUE;
266
267 struct event_passthrough *e =
268 event_create_passthrough(rcpt->event)->
269 set_name("smtp_server_transaction_rcpt_finished");
270 smtp_server_reply_add_to_event(reply, e);
271
272 e_debug(e->event(), "Finished");
273 }
274
275 #undef smtp_server_recipient_add_hook
smtp_server_recipient_add_hook(struct smtp_server_recipient * rcpt,enum smtp_server_recipient_hook_type type,smtp_server_rcpt_func_t func,void * context)276 void smtp_server_recipient_add_hook(struct smtp_server_recipient *rcpt,
277 enum smtp_server_recipient_hook_type type,
278 smtp_server_rcpt_func_t func, void *context)
279 {
280 struct smtp_server_recipient_private *prcpt =
281 (struct smtp_server_recipient_private *)rcpt;
282 struct smtp_server_recipient_hook *hook;
283
284 i_assert(func != NULL);
285
286 hook = prcpt->hooks_head;
287 while (hook != NULL) {
288 /* No double registrations */
289 i_assert(hook->type != type || hook->func != func);
290
291 hook = hook->next;
292 }
293
294 hook = p_new(rcpt->pool, struct smtp_server_recipient_hook, 1);
295 hook->type = type;
296 hook->func = func;
297 hook->context = context;
298
299 DLLIST2_APPEND(&prcpt->hooks_head, &prcpt->hooks_tail, hook);
300 }
301
302 #undef smtp_server_recipient_remove_hook
smtp_server_recipient_remove_hook(struct smtp_server_recipient * rcpt,enum smtp_server_recipient_hook_type type,smtp_server_rcpt_func_t * func)303 void smtp_server_recipient_remove_hook(
304 struct smtp_server_recipient *rcpt,
305 enum smtp_server_recipient_hook_type type,
306 smtp_server_rcpt_func_t *func)
307 {
308 struct smtp_server_recipient_private *prcpt =
309 (struct smtp_server_recipient_private *)rcpt;
310 struct smtp_server_recipient_hook *hook;
311 bool found = FALSE;
312
313 hook = prcpt->hooks_head;
314 while (hook != NULL) {
315 struct smtp_server_recipient_hook *hook_next = hook->next;
316
317 if (hook->type == type && hook->func == func) {
318 DLLIST2_REMOVE(&prcpt->hooks_head, &prcpt->hooks_tail,
319 hook);
320 found = TRUE;
321 break;
322 }
323
324 hook = hook_next;
325 }
326 i_assert(found);
327 }
328
smtp_server_recipient_call_hooks(struct smtp_server_recipient ** _rcpt,enum smtp_server_recipient_hook_type type)329 bool smtp_server_recipient_call_hooks(
330 struct smtp_server_recipient **_rcpt,
331 enum smtp_server_recipient_hook_type type)
332 {
333 struct smtp_server_recipient *rcpt = *_rcpt;
334 struct smtp_server_recipient_private *prcpt =
335 (struct smtp_server_recipient_private *)rcpt;
336 struct smtp_server_recipient_hook *hook;
337
338 if (type != SMTP_SERVER_RECIPIENT_HOOK_DESTROY)
339 smtp_server_recipient_ref(rcpt);
340
341 hook = prcpt->hooks_head;
342 while (hook != NULL) {
343 struct smtp_server_recipient_hook *hook_next = hook->next;
344
345 if (hook->type == type) {
346 DLLIST2_REMOVE(&prcpt->hooks_head, &prcpt->hooks_tail,
347 hook);
348 hook->func(rcpt, hook->context);
349 }
350
351 hook = hook_next;
352 }
353
354 if (type != SMTP_SERVER_RECIPIENT_HOOK_DESTROY) {
355 if (!smtp_server_recipient_unref(&rcpt)) {
356 *_rcpt = NULL;
357 return FALSE;
358 }
359 }
360 return TRUE;
361 }
362