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