1 |
|
|
/* $OpenBSD: lka_session.c,v 1.81 2017/05/26 21:30:00 gilles Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Copyright (c) 2011 Gilles Chehade <gilles@poolp.org> |
5 |
|
|
* Copyright (c) 2012 Eric Faurot <eric@openbsd.org> |
6 |
|
|
* |
7 |
|
|
* Permission to use, copy, modify, and distribute this software for any |
8 |
|
|
* purpose with or without fee is hereby granted, provided that the above |
9 |
|
|
* copyright notice and this permission notice appear in all copies. |
10 |
|
|
* |
11 |
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
12 |
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
13 |
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
14 |
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
15 |
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
16 |
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
17 |
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
18 |
|
|
*/ |
19 |
|
|
|
20 |
|
|
#include <sys/types.h> |
21 |
|
|
#include <sys/queue.h> |
22 |
|
|
#include <sys/tree.h> |
23 |
|
|
#include <sys/socket.h> |
24 |
|
|
#include <sys/wait.h> |
25 |
|
|
|
26 |
|
|
#include <netinet/in.h> |
27 |
|
|
|
28 |
|
|
#include <ctype.h> |
29 |
|
|
#include <errno.h> |
30 |
|
|
#include <event.h> |
31 |
|
|
#include <imsg.h> |
32 |
|
|
#include <resolv.h> |
33 |
|
|
#include <pwd.h> |
34 |
|
|
#include <signal.h> |
35 |
|
|
#include <stdio.h> |
36 |
|
|
#include <stdlib.h> |
37 |
|
|
#include <string.h> |
38 |
|
|
#include <unistd.h> |
39 |
|
|
#include <limits.h> |
40 |
|
|
|
41 |
|
|
#include "smtpd.h" |
42 |
|
|
#include "log.h" |
43 |
|
|
|
44 |
|
|
#define EXPAND_DEPTH 10 |
45 |
|
|
|
46 |
|
|
#define F_WAITING 0x01 |
47 |
|
|
|
48 |
|
|
struct lka_session { |
49 |
|
|
uint64_t id; /* given by smtp */ |
50 |
|
|
|
51 |
|
|
TAILQ_HEAD(, envelope) deliverylist; |
52 |
|
|
struct expand expand; |
53 |
|
|
|
54 |
|
|
int flags; |
55 |
|
|
int error; |
56 |
|
|
const char *errormsg; |
57 |
|
|
struct envelope envelope; |
58 |
|
|
struct xnodes nodes; |
59 |
|
|
/* waiting for fwdrq */ |
60 |
|
|
struct rule *rule; |
61 |
|
|
struct expandnode *node; |
62 |
|
|
}; |
63 |
|
|
|
64 |
|
|
static void lka_expand(struct lka_session *, struct rule *, |
65 |
|
|
struct expandnode *); |
66 |
|
|
static void lka_submit(struct lka_session *, struct rule *, |
67 |
|
|
struct expandnode *); |
68 |
|
|
static void lka_resume(struct lka_session *); |
69 |
|
|
|
70 |
|
|
static int init; |
71 |
|
|
static struct tree sessions; |
72 |
|
|
|
73 |
|
|
void |
74 |
|
|
lka_session(uint64_t id, struct envelope *envelope) |
75 |
|
|
{ |
76 |
|
|
struct lka_session *lks; |
77 |
|
|
struct expandnode xn; |
78 |
|
|
|
79 |
|
|
if (init == 0) { |
80 |
|
|
init = 1; |
81 |
|
|
tree_init(&sessions); |
82 |
|
|
} |
83 |
|
|
|
84 |
|
|
lks = xcalloc(1, sizeof(*lks), "lka_session"); |
85 |
|
|
lks->id = id; |
86 |
|
|
RB_INIT(&lks->expand.tree); |
87 |
|
|
TAILQ_INIT(&lks->deliverylist); |
88 |
|
|
tree_xset(&sessions, lks->id, lks); |
89 |
|
|
|
90 |
|
|
lks->envelope = *envelope; |
91 |
|
|
|
92 |
|
|
TAILQ_INIT(&lks->nodes); |
93 |
|
|
memset(&xn, 0, sizeof xn); |
94 |
|
|
xn.type = EXPAND_ADDRESS; |
95 |
|
|
xn.u.mailaddr = lks->envelope.rcpt; |
96 |
|
|
lks->expand.rule = NULL; |
97 |
|
|
lks->expand.queue = &lks->nodes; |
98 |
|
|
expand_insert(&lks->expand, &xn); |
99 |
|
|
lka_resume(lks); |
100 |
|
|
} |
101 |
|
|
|
102 |
|
|
void |
103 |
|
|
lka_session_forward_reply(struct forward_req *fwreq, int fd) |
104 |
|
|
{ |
105 |
|
|
struct lka_session *lks; |
106 |
|
|
struct rule *rule; |
107 |
|
|
struct expandnode *xn; |
108 |
|
|
int ret; |
109 |
|
|
|
110 |
|
|
lks = tree_xget(&sessions, fwreq->id); |
111 |
|
|
xn = lks->node; |
112 |
|
|
rule = lks->rule; |
113 |
|
|
|
114 |
|
|
lks->flags &= ~F_WAITING; |
115 |
|
|
|
116 |
|
|
switch (fwreq->status) { |
117 |
|
|
case 0: |
118 |
|
|
/* permanent failure while lookup ~/.forward */ |
119 |
|
|
log_trace(TRACE_EXPAND, "expand: ~/.forward failed for user %s", |
120 |
|
|
fwreq->user); |
121 |
|
|
lks->error = LKA_PERMFAIL; |
122 |
|
|
break; |
123 |
|
|
case 1: |
124 |
|
|
if (fd == -1) { |
125 |
|
|
if (lks->expand.rule->r_forwardonly) { |
126 |
|
|
log_trace(TRACE_EXPAND, "expand: no .forward " |
127 |
|
|
"for user %s on forward-only rule", fwreq->user); |
128 |
|
|
lks->error = LKA_TEMPFAIL; |
129 |
|
|
} |
130 |
|
|
else if (lks->expand.rule->r_action == A_NONE) { |
131 |
|
|
log_trace(TRACE_EXPAND, "expand: no .forward " |
132 |
|
|
"for user %s and no default action on rule", fwreq->user); |
133 |
|
|
lks->error = LKA_PERMFAIL; |
134 |
|
|
} |
135 |
|
|
else { |
136 |
|
|
log_trace(TRACE_EXPAND, "expand: no .forward for " |
137 |
|
|
"user %s, just deliver", fwreq->user); |
138 |
|
|
lka_submit(lks, rule, xn); |
139 |
|
|
} |
140 |
|
|
} |
141 |
|
|
else { |
142 |
|
|
/* expand for the current user and rule */ |
143 |
|
|
lks->expand.rule = rule; |
144 |
|
|
lks->expand.parent = xn; |
145 |
|
|
lks->expand.alias = 0; |
146 |
|
|
xn->mapping = rule->r_mapping; |
147 |
|
|
xn->userbase = rule->r_userbase; |
148 |
|
|
/* forwards_get() will close the descriptor no matter what */ |
149 |
|
|
ret = forwards_get(fd, &lks->expand); |
150 |
|
|
if (ret == -1) { |
151 |
|
|
log_trace(TRACE_EXPAND, "expand: temporary " |
152 |
|
|
"forward error for user %s", fwreq->user); |
153 |
|
|
lks->error = LKA_TEMPFAIL; |
154 |
|
|
} |
155 |
|
|
else if (ret == 0) { |
156 |
|
|
if (lks->expand.rule->r_forwardonly) { |
157 |
|
|
log_trace(TRACE_EXPAND, "expand: empty .forward " |
158 |
|
|
"for user %s on forward-only rule", fwreq->user); |
159 |
|
|
lks->error = LKA_TEMPFAIL; |
160 |
|
|
} |
161 |
|
|
else if (lks->expand.rule->r_action == A_NONE) { |
162 |
|
|
log_trace(TRACE_EXPAND, "expand: empty .forward " |
163 |
|
|
"for user %s and no default action on rule", fwreq->user); |
164 |
|
|
lks->error = LKA_PERMFAIL; |
165 |
|
|
} |
166 |
|
|
else { |
167 |
|
|
log_trace(TRACE_EXPAND, "expand: empty .forward " |
168 |
|
|
"for user %s, just deliver", fwreq->user); |
169 |
|
|
lka_submit(lks, rule, xn); |
170 |
|
|
} |
171 |
|
|
} |
172 |
|
|
} |
173 |
|
|
break; |
174 |
|
|
default: |
175 |
|
|
/* temporary failure while looking up ~/.forward */ |
176 |
|
|
lks->error = LKA_TEMPFAIL; |
177 |
|
|
} |
178 |
|
|
|
179 |
|
|
lka_resume(lks); |
180 |
|
|
} |
181 |
|
|
|
182 |
|
|
static void |
183 |
|
|
lka_resume(struct lka_session *lks) |
184 |
|
|
{ |
185 |
|
|
struct envelope *ep; |
186 |
|
|
struct expandnode *xn; |
187 |
|
|
|
188 |
|
|
if (lks->error) |
189 |
|
|
goto error; |
190 |
|
|
|
191 |
|
|
/* pop next node and expand it */ |
192 |
|
|
while ((xn = TAILQ_FIRST(&lks->nodes))) { |
193 |
|
|
TAILQ_REMOVE(&lks->nodes, xn, tq_entry); |
194 |
|
|
lka_expand(lks, xn->rule, xn); |
195 |
|
|
if (lks->flags & F_WAITING) |
196 |
|
|
return; |
197 |
|
|
if (lks->error) |
198 |
|
|
goto error; |
199 |
|
|
} |
200 |
|
|
|
201 |
|
|
/* delivery list is empty, reject */ |
202 |
|
|
if (TAILQ_FIRST(&lks->deliverylist) == NULL) { |
203 |
|
|
log_trace(TRACE_EXPAND, "expand: lka_done: expanded to empty " |
204 |
|
|
"delivery list"); |
205 |
|
|
lks->error = LKA_PERMFAIL; |
206 |
|
|
} |
207 |
|
|
error: |
208 |
|
|
if (lks->error) { |
209 |
|
|
m_create(p_pony, IMSG_SMTP_EXPAND_RCPT, 0, 0, -1); |
210 |
|
|
m_add_id(p_pony, lks->id); |
211 |
|
|
m_add_int(p_pony, lks->error); |
212 |
|
|
|
213 |
|
|
if (lks->errormsg) |
214 |
|
|
m_add_string(p_pony, lks->errormsg); |
215 |
|
|
else { |
216 |
|
|
if (lks->error == LKA_PERMFAIL) |
217 |
|
|
m_add_string(p_pony, "550 Invalid recipient"); |
218 |
|
|
else if (lks->error == LKA_TEMPFAIL) |
219 |
|
|
m_add_string(p_pony, "451 Temporary failure"); |
220 |
|
|
} |
221 |
|
|
|
222 |
|
|
m_close(p_pony); |
223 |
|
|
while ((ep = TAILQ_FIRST(&lks->deliverylist)) != NULL) { |
224 |
|
|
TAILQ_REMOVE(&lks->deliverylist, ep, entry); |
225 |
|
|
free(ep); |
226 |
|
|
} |
227 |
|
|
} |
228 |
|
|
else { |
229 |
|
|
/* Process the delivery list and submit envelopes to queue */ |
230 |
|
|
while ((ep = TAILQ_FIRST(&lks->deliverylist)) != NULL) { |
231 |
|
|
TAILQ_REMOVE(&lks->deliverylist, ep, entry); |
232 |
|
|
m_create(p_queue, IMSG_LKA_ENVELOPE_SUBMIT, 0, 0, -1); |
233 |
|
|
m_add_id(p_queue, lks->id); |
234 |
|
|
m_add_envelope(p_queue, ep); |
235 |
|
|
m_close(p_queue); |
236 |
|
|
free(ep); |
237 |
|
|
} |
238 |
|
|
|
239 |
|
|
m_create(p_queue, IMSG_LKA_ENVELOPE_COMMIT, 0, 0, -1); |
240 |
|
|
m_add_id(p_queue, lks->id); |
241 |
|
|
m_close(p_queue); |
242 |
|
|
} |
243 |
|
|
|
244 |
|
|
expand_clear(&lks->expand); |
245 |
|
|
tree_xpop(&sessions, lks->id); |
246 |
|
|
free(lks); |
247 |
|
|
} |
248 |
|
|
|
249 |
|
|
static void |
250 |
|
|
lka_expand(struct lka_session *lks, struct rule *rule, struct expandnode *xn) |
251 |
|
|
{ |
252 |
|
|
struct forward_req fwreq; |
253 |
|
|
struct envelope ep; |
254 |
|
|
struct expandnode node; |
255 |
|
|
struct mailaddr maddr; |
256 |
|
|
int r; |
257 |
|
|
union lookup lk; |
258 |
|
|
char *tag; |
259 |
|
|
|
260 |
|
|
if (xn->depth >= EXPAND_DEPTH) { |
261 |
|
|
log_trace(TRACE_EXPAND, "expand: lka_expand: node too deep."); |
262 |
|
|
lks->error = LKA_PERMFAIL; |
263 |
|
|
return; |
264 |
|
|
} |
265 |
|
|
|
266 |
|
|
switch (xn->type) { |
267 |
|
|
case EXPAND_INVALID: |
268 |
|
|
case EXPAND_INCLUDE: |
269 |
|
|
fatalx("lka_expand: unexpected type"); |
270 |
|
|
break; |
271 |
|
|
|
272 |
|
|
case EXPAND_ADDRESS: |
273 |
|
|
|
274 |
|
|
log_trace(TRACE_EXPAND, "expand: lka_expand: address: %s@%s " |
275 |
|
|
"[depth=%d]", |
276 |
|
|
xn->u.mailaddr.user, xn->u.mailaddr.domain, xn->depth); |
277 |
|
|
|
278 |
|
|
/* Pass the node through the ruleset */ |
279 |
|
|
ep = lks->envelope; |
280 |
|
|
ep.dest = xn->u.mailaddr; |
281 |
|
|
if (xn->parent) /* nodes with parent are forward addresses */ |
282 |
|
|
ep.flags |= EF_INTERNAL; |
283 |
|
|
rule = ruleset_match(&ep); |
284 |
|
|
if (rule == NULL || rule->r_decision == R_REJECT) { |
285 |
|
|
lks->error = (errno == EAGAIN) ? |
286 |
|
|
LKA_TEMPFAIL : LKA_PERMFAIL; |
287 |
|
|
break; |
288 |
|
|
} |
289 |
|
|
|
290 |
|
|
xn->mapping = rule->r_mapping; |
291 |
|
|
xn->userbase = rule->r_userbase; |
292 |
|
|
|
293 |
|
|
if (rule->r_action == A_RELAY || rule->r_action == A_RELAYVIA) { |
294 |
|
|
lka_submit(lks, rule, xn); |
295 |
|
|
} |
296 |
|
|
else if (rule->r_desttype == DEST_VDOM) { |
297 |
|
|
/* expand */ |
298 |
|
|
lks->expand.rule = rule; |
299 |
|
|
lks->expand.parent = xn; |
300 |
|
|
lks->expand.alias = 1; |
301 |
|
|
|
302 |
|
|
/* temporary replace the mailaddr with a copy where |
303 |
|
|
* we eventually strip the '+'-part before lookup. |
304 |
|
|
*/ |
305 |
|
|
maddr = xn->u.mailaddr; |
306 |
|
|
xlowercase(maddr.user, xn->u.mailaddr.user, |
307 |
|
|
sizeof maddr.user); |
308 |
|
|
r = aliases_virtual_get(&lks->expand, &maddr); |
309 |
|
|
if (r == -1) { |
310 |
|
|
lks->error = LKA_TEMPFAIL; |
311 |
|
|
log_trace(TRACE_EXPAND, "expand: lka_expand: " |
312 |
|
|
"error in virtual alias lookup"); |
313 |
|
|
} |
314 |
|
|
else if (r == 0) { |
315 |
|
|
lks->error = LKA_PERMFAIL; |
316 |
|
|
log_trace(TRACE_EXPAND, "expand: lka_expand: " |
317 |
|
|
"no aliases for virtual"); |
318 |
|
|
} |
319 |
|
|
} |
320 |
|
|
else { |
321 |
|
|
lks->expand.rule = rule; |
322 |
|
|
lks->expand.parent = xn; |
323 |
|
|
lks->expand.alias = 1; |
324 |
|
|
memset(&node, 0, sizeof node); |
325 |
|
|
node.type = EXPAND_USERNAME; |
326 |
|
|
xlowercase(node.u.user, xn->u.mailaddr.user, |
327 |
|
|
sizeof node.u.user); |
328 |
|
|
node.mapping = rule->r_mapping; |
329 |
|
|
node.userbase = rule->r_userbase; |
330 |
|
|
expand_insert(&lks->expand, &node); |
331 |
|
|
} |
332 |
|
|
break; |
333 |
|
|
|
334 |
|
|
case EXPAND_USERNAME: |
335 |
|
|
log_trace(TRACE_EXPAND, "expand: lka_expand: username: %s " |
336 |
|
|
"[depth=%d]", xn->u.user, xn->depth); |
337 |
|
|
|
338 |
|
|
if (xn->sameuser) { |
339 |
|
|
log_trace(TRACE_EXPAND, "expand: lka_expand: same " |
340 |
|
|
"user, submitting"); |
341 |
|
|
lka_submit(lks, rule, xn); |
342 |
|
|
break; |
343 |
|
|
} |
344 |
|
|
|
345 |
|
|
/* expand aliases with the given rule */ |
346 |
|
|
lks->expand.rule = rule; |
347 |
|
|
lks->expand.parent = xn; |
348 |
|
|
lks->expand.alias = 1; |
349 |
|
|
xn->mapping = rule->r_mapping; |
350 |
|
|
xn->userbase = rule->r_userbase; |
351 |
|
|
if (rule->r_mapping) { |
352 |
|
|
r = aliases_get(&lks->expand, xn->u.user); |
353 |
|
|
if (r == -1) { |
354 |
|
|
log_trace(TRACE_EXPAND, "expand: lka_expand: " |
355 |
|
|
"error in alias lookup"); |
356 |
|
|
lks->error = LKA_TEMPFAIL; |
357 |
|
|
} |
358 |
|
|
if (r) |
359 |
|
|
break; |
360 |
|
|
} |
361 |
|
|
|
362 |
|
|
/* gilles+hackers@ -> gilles@ */ |
363 |
|
|
if ((tag = strchr(xn->u.user, *env->sc_subaddressing_delim)) != NULL) |
364 |
|
|
*tag++ = '\0'; |
365 |
|
|
|
366 |
|
|
r = table_lookup(rule->r_userbase, NULL, xn->u.user, K_USERINFO, &lk); |
367 |
|
|
if (r == -1) { |
368 |
|
|
log_trace(TRACE_EXPAND, "expand: lka_expand: " |
369 |
|
|
"backend error while searching user"); |
370 |
|
|
lks->error = LKA_TEMPFAIL; |
371 |
|
|
break; |
372 |
|
|
} |
373 |
|
|
if (r == 0) { |
374 |
|
|
log_trace(TRACE_EXPAND, "expand: lka_expand: " |
375 |
|
|
"user-part does not match system user"); |
376 |
|
|
lks->error = LKA_PERMFAIL; |
377 |
|
|
break; |
378 |
|
|
} |
379 |
|
|
|
380 |
|
|
/* no aliases found, query forward file */ |
381 |
|
|
lks->rule = rule; |
382 |
|
|
lks->node = xn; |
383 |
|
|
|
384 |
|
|
memset(&fwreq, 0, sizeof(fwreq)); |
385 |
|
|
fwreq.id = lks->id; |
386 |
|
|
(void)strlcpy(fwreq.user, lk.userinfo.username, sizeof(fwreq.user)); |
387 |
|
|
(void)strlcpy(fwreq.directory, lk.userinfo.directory, sizeof(fwreq.directory)); |
388 |
|
|
fwreq.uid = lk.userinfo.uid; |
389 |
|
|
fwreq.gid = lk.userinfo.gid; |
390 |
|
|
|
391 |
|
|
m_compose(p_parent, IMSG_LKA_OPEN_FORWARD, 0, 0, -1, |
392 |
|
|
&fwreq, sizeof(fwreq)); |
393 |
|
|
lks->flags |= F_WAITING; |
394 |
|
|
break; |
395 |
|
|
|
396 |
|
|
case EXPAND_FILENAME: |
397 |
|
|
if (rule->r_forwardonly) { |
398 |
|
|
log_trace(TRACE_EXPAND, "expand: filename matched on forward-only rule"); |
399 |
|
|
lks->error = LKA_TEMPFAIL; |
400 |
|
|
break; |
401 |
|
|
} |
402 |
|
|
log_trace(TRACE_EXPAND, "expand: lka_expand: filename: %s " |
403 |
|
|
"[depth=%d]", xn->u.buffer, xn->depth); |
404 |
|
|
lka_submit(lks, rule, xn); |
405 |
|
|
break; |
406 |
|
|
|
407 |
|
|
case EXPAND_ERROR: |
408 |
|
|
if (rule->r_forwardonly) { |
409 |
|
|
log_trace(TRACE_EXPAND, "expand: error matched on forward-only rule"); |
410 |
|
|
lks->error = LKA_TEMPFAIL; |
411 |
|
|
break; |
412 |
|
|
} |
413 |
|
|
log_trace(TRACE_EXPAND, "expand: lka_expand: error: %s " |
414 |
|
|
"[depth=%d]", xn->u.buffer, xn->depth); |
415 |
|
|
if (xn->u.buffer[0] == '4') |
416 |
|
|
lks->error = LKA_TEMPFAIL; |
417 |
|
|
else if (xn->u.buffer[0] == '5') |
418 |
|
|
lks->error = LKA_PERMFAIL; |
419 |
|
|
lks->errormsg = xn->u.buffer; |
420 |
|
|
break; |
421 |
|
|
|
422 |
|
|
case EXPAND_FILTER: |
423 |
|
|
if (rule->r_forwardonly) { |
424 |
|
|
log_trace(TRACE_EXPAND, "expand: filter matched on forward-only rule"); |
425 |
|
|
lks->error = LKA_TEMPFAIL; |
426 |
|
|
break; |
427 |
|
|
} |
428 |
|
|
log_trace(TRACE_EXPAND, "expand: lka_expand: filter: %s " |
429 |
|
|
"[depth=%d]", xn->u.buffer, xn->depth); |
430 |
|
|
lka_submit(lks, rule, xn); |
431 |
|
|
break; |
432 |
|
|
|
433 |
|
|
case EXPAND_MAILDIR: |
434 |
|
|
log_trace(TRACE_EXPAND, "expand: lka_expand: maildir: %s " |
435 |
|
|
"[depth=%d]", xn->u.buffer, xn->depth); |
436 |
|
|
r = table_lookup(rule->r_userbase, NULL, |
437 |
|
|
xn->parent->u.user, K_USERINFO, &lk); |
438 |
|
|
if (r == -1) { |
439 |
|
|
log_trace(TRACE_EXPAND, "expand: lka_expand: maildir: " |
440 |
|
|
"backend error while searching user"); |
441 |
|
|
lks->error = LKA_TEMPFAIL; |
442 |
|
|
break; |
443 |
|
|
} |
444 |
|
|
if (r == 0) { |
445 |
|
|
log_trace(TRACE_EXPAND, "expand: lka_expand: maildir: " |
446 |
|
|
"user-part does not match system user"); |
447 |
|
|
lks->error = LKA_PERMFAIL; |
448 |
|
|
break; |
449 |
|
|
} |
450 |
|
|
|
451 |
|
|
lka_submit(lks, rule, xn); |
452 |
|
|
break; |
453 |
|
|
} |
454 |
|
|
} |
455 |
|
|
|
456 |
|
|
static struct expandnode * |
457 |
|
|
lka_find_ancestor(struct expandnode *xn, enum expand_type type) |
458 |
|
|
{ |
459 |
|
|
while (xn && (xn->type != type)) |
460 |
|
|
xn = xn->parent; |
461 |
|
|
if (xn == NULL) { |
462 |
|
|
log_warnx("warn: lka_find_ancestor: no ancestors of type %d", |
463 |
|
|
type); |
464 |
|
|
fatalx(NULL); |
465 |
|
|
} |
466 |
|
|
return (xn); |
467 |
|
|
} |
468 |
|
|
|
469 |
|
|
static void |
470 |
|
|
lka_submit(struct lka_session *lks, struct rule *rule, struct expandnode *xn) |
471 |
|
|
{ |
472 |
|
|
union lookup lk; |
473 |
|
|
struct envelope *ep; |
474 |
|
|
struct expandnode *xn2; |
475 |
|
|
int r; |
476 |
|
|
|
477 |
|
|
ep = xmemdup(&lks->envelope, sizeof *ep, "lka_submit"); |
478 |
|
|
ep->expire = rule->r_qexpire; |
479 |
|
|
|
480 |
|
|
switch (rule->r_action) { |
481 |
|
|
case A_RELAY: |
482 |
|
|
case A_RELAYVIA: |
483 |
|
|
if (xn->type != EXPAND_ADDRESS) |
484 |
|
|
fatalx("lka_deliver: expect address"); |
485 |
|
|
ep->type = D_MTA; |
486 |
|
|
ep->dest = xn->u.mailaddr; |
487 |
|
|
ep->agent.mta.relay = rule->r_value.relayhost; |
488 |
|
|
|
489 |
|
|
/* only rewrite if not a bounce */ |
490 |
|
|
if (ep->sender.user[0] && rule->r_as && rule->r_as->user[0]) |
491 |
|
|
(void)strlcpy(ep->sender.user, rule->r_as->user, |
492 |
|
|
sizeof ep->sender.user); |
493 |
|
|
if (ep->sender.user[0] && rule->r_as && rule->r_as->domain[0]) |
494 |
|
|
(void)strlcpy(ep->sender.domain, rule->r_as->domain, |
495 |
|
|
sizeof ep->sender.domain); |
496 |
|
|
break; |
497 |
|
|
case A_NONE: |
498 |
|
|
case A_MBOX: |
499 |
|
|
case A_MAILDIR: |
500 |
|
|
case A_FILENAME: |
501 |
|
|
case A_MDA: |
502 |
|
|
case A_LMTP: |
503 |
|
|
ep->type = D_MDA; |
504 |
|
|
ep->dest = lka_find_ancestor(xn, EXPAND_ADDRESS)->u.mailaddr; |
505 |
|
|
|
506 |
|
|
/* set username */ |
507 |
|
|
if ((xn->type == EXPAND_FILTER || xn->type == EXPAND_FILENAME) |
508 |
|
|
&& xn->alias) { |
509 |
|
|
(void)strlcpy(ep->agent.mda.username, SMTPD_USER, |
510 |
|
|
sizeof(ep->agent.mda.username)); |
511 |
|
|
} |
512 |
|
|
else { |
513 |
|
|
xn2 = lka_find_ancestor(xn, EXPAND_USERNAME); |
514 |
|
|
(void)strlcpy(ep->agent.mda.username, xn2->u.user, |
515 |
|
|
sizeof(ep->agent.mda.username)); |
516 |
|
|
} |
517 |
|
|
|
518 |
|
|
r = table_lookup(rule->r_userbase, NULL, ep->agent.mda.username, |
519 |
|
|
K_USERINFO, &lk); |
520 |
|
|
if (r <= 0) { |
521 |
|
|
lks->error = (r == -1) ? LKA_TEMPFAIL : LKA_PERMFAIL; |
522 |
|
|
free(ep); |
523 |
|
|
return; |
524 |
|
|
} |
525 |
|
|
(void)strlcpy(ep->agent.mda.usertable, rule->r_userbase->t_name, |
526 |
|
|
sizeof ep->agent.mda.usertable); |
527 |
|
|
(void)strlcpy(ep->agent.mda.username, lk.userinfo.username, |
528 |
|
|
sizeof ep->agent.mda.username); |
529 |
|
|
strlcpy(ep->agent.mda.delivery_user, rule->r_delivery_user, |
530 |
|
|
sizeof ep->agent.mda.delivery_user); |
531 |
|
|
|
532 |
|
|
if (xn->type == EXPAND_FILENAME) { |
533 |
|
|
ep->agent.mda.method = A_FILENAME; |
534 |
|
|
(void)strlcpy(ep->agent.mda.buffer, xn->u.buffer, |
535 |
|
|
sizeof ep->agent.mda.buffer); |
536 |
|
|
} |
537 |
|
|
else if (xn->type == EXPAND_FILTER) { |
538 |
|
|
ep->agent.mda.method = A_MDA; |
539 |
|
|
(void)strlcpy(ep->agent.mda.buffer, xn->u.buffer, |
540 |
|
|
sizeof ep->agent.mda.buffer); |
541 |
|
|
} |
542 |
|
|
else if (xn->type == EXPAND_USERNAME) { |
543 |
|
|
ep->agent.mda.method = rule->r_action; |
544 |
|
|
(void)strlcpy(ep->agent.mda.buffer, rule->r_value.buffer, |
545 |
|
|
sizeof ep->agent.mda.buffer); |
546 |
|
|
} |
547 |
|
|
else if (xn->type == EXPAND_MAILDIR) { |
548 |
|
|
ep->agent.mda.method = A_MAILDIR; |
549 |
|
|
(void)strlcpy(ep->agent.mda.buffer, xn->u.buffer, |
550 |
|
|
sizeof ep->agent.mda.buffer); |
551 |
|
|
} |
552 |
|
|
else |
553 |
|
|
fatalx("lka_deliver: bad node type"); |
554 |
|
|
|
555 |
|
|
r = mda_expand_format(ep->agent.mda.buffer, |
556 |
|
|
sizeof(ep->agent.mda.buffer), ep, &lk.userinfo); |
557 |
|
|
if (!r) { |
558 |
|
|
lks->error = LKA_TEMPFAIL; |
559 |
|
|
log_warnx("warn: format string error while" |
560 |
|
|
" expanding for user %s", ep->agent.mda.username); |
561 |
|
|
free(ep); |
562 |
|
|
return; |
563 |
|
|
} |
564 |
|
|
break; |
565 |
|
|
default: |
566 |
|
|
fatalx("lka_submit: bad rule action"); |
567 |
|
|
} |
568 |
|
|
|
569 |
|
|
TAILQ_INSERT_TAIL(&lks->deliverylist, ep, entry); |
570 |
|
|
} |