1*c12b402cStb /* $OpenBSD: lka.c,v 1.250 2024/06/11 16:30:06 tb Exp $ */
21f3c2bcfSsobrado
33ef9cbf7Sgilles /*
43ef9cbf7Sgilles * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
565c4fdfbSgilles * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
665c4fdfbSgilles * Copyright (c) 2012 Eric Faurot <eric@faurot.net>
73ef9cbf7Sgilles *
83ef9cbf7Sgilles * Permission to use, copy, modify, and distribute this software for any
93ef9cbf7Sgilles * purpose with or without fee is hereby granted, provided that the above
103ef9cbf7Sgilles * copyright notice and this permission notice appear in all copies.
113ef9cbf7Sgilles *
123ef9cbf7Sgilles * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
133ef9cbf7Sgilles * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
143ef9cbf7Sgilles * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
153ef9cbf7Sgilles * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
163ef9cbf7Sgilles * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
173ef9cbf7Sgilles * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
183ef9cbf7Sgilles * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
193ef9cbf7Sgilles */
203ef9cbf7Sgilles
2197c17d55Sjacekm #include <sys/wait.h>
223ef9cbf7Sgilles
2397c17d55Sjacekm #include <errno.h>
2412baa4f7Sjacekm #include <pwd.h>
25439d0b42Schl #include <signal.h>
263ef9cbf7Sgilles #include <stdlib.h>
273ef9cbf7Sgilles #include <unistd.h>
283ef9cbf7Sgilles
293ef9cbf7Sgilles #include "smtpd.h"
305eb8dddaSgilles #include "log.h"
313ef9cbf7Sgilles
3265c4fdfbSgilles static void lka_imsg(struct mproc *, struct imsg *);
33be925435Sgilles static void lka_shutdown(void);
34be925435Sgilles static void lka_sig_handler(int, short, void *);
3565c4fdfbSgilles static int lka_authenticate(const char *, const char *, const char *);
3665c4fdfbSgilles static int lka_credentials(const char *, const char *, char *, size_t);
3765c4fdfbSgilles static int lka_userinfo(const char *, const char *, struct userinfo *);
3865c4fdfbSgilles static int lka_addrname(const char *, const struct sockaddr *,
3965c4fdfbSgilles struct addrname *);
40d5f10ab5Sgilles static int lka_mailaddrmap(const char *, const char *, const struct mailaddr *);
413ef9cbf7Sgilles
42ec69ed85Sgilles static void proc_timeout(int fd, short event, void *p);
43ec69ed85Sgilles
44ec69ed85Sgilles struct event ev_proc_ready;
45ec69ed85Sgilles
46be925435Sgilles static void
lka_imsg(struct mproc * p,struct imsg * imsg)4765c4fdfbSgilles lka_imsg(struct mproc *p, struct imsg *imsg)
48ed1929b6Sjacekm {
4965c4fdfbSgilles struct table *table;
50510586acSclaudio int ret, fd;
5165c4fdfbSgilles struct sockaddr_storage ss;
5265c4fdfbSgilles struct userinfo userinfo;
5365c4fdfbSgilles struct addrname addrname;
5465c4fdfbSgilles struct envelope evp;
5506405042Ssunil struct mailaddr maddr;
5665c4fdfbSgilles struct msg m;
57299c4efeSeric union lookup lk;
58953aae25Sderaadt char buf[LINE_MAX];
59a93e09f5Sgilles const char *tablename, *username, *password, *label, *procname;
6065c4fdfbSgilles uint64_t reqid;
6165c4fdfbSgilles int v;
624e92310aSgilles struct timeval tv;
63d738de61Sgilles const char *direction;
642a5af9afSgilles const char *rdns;
65a742ecdcSgilles const char *command;
66a742ecdcSgilles const char *response;
67b7d8690dSgilles const char *ciphers;
687929fb13Sgilles const char *address;
69233a267cSmartijn const char *domain;
70f9257e33Sgilles const char *helomethod;
717ec3fc38Sgilles const char *heloname;
72ec69ed85Sgilles const char *filter_name;
73a742ecdcSgilles const char *result;
74b7d8690dSgilles struct sockaddr_storage ss_src, ss_dest;
75b0d3076dSgilles int filter_response;
76d7b0dc3bSgilles int filter_phase;
77d7b0dc3bSgilles const char *filter_param;
7871b9078fSgilles uint32_t msgid;
7926bbc7b9Sgilles uint32_t subsystems;
8071b9078fSgilles uint64_t evpid;
8171b9078fSgilles size_t msgsz;
827929fb13Sgilles int ok;
837bbc0d03Sgilles int fcrdns;
84ed1929b6Sjacekm
8543962b9cSeric if (imsg == NULL)
8643962b9cSeric lka_shutdown();
8743962b9cSeric
88ffdd47f9Seric switch (imsg->hdr.type) {
89ffdd47f9Seric
9001eba458Seric case IMSG_GETADDRINFO:
9101eba458Seric case IMSG_GETNAMEINFO:
9201361951Seric case IMSG_RES_QUERY:
9301eba458Seric resolver_dispatch_request(p, imsg);
9401eba458Seric return;
9501eba458Seric
96ffdd47f9Seric case IMSG_MTA_DNS_HOST:
97ffdd47f9Seric case IMSG_MTA_DNS_MX:
98ffdd47f9Seric case IMSG_MTA_DNS_MX_PREFERENCE:
9965c4fdfbSgilles dns_imsg(p, imsg);
100ed1929b6Sjacekm return;
101ed1929b6Sjacekm
10206405042Ssunil case IMSG_SMTP_CHECK_SENDER:
10306405042Ssunil m_msg(&m, imsg);
10406405042Ssunil m_get_id(&m, &reqid);
10506405042Ssunil m_get_string(&m, &tablename);
10606405042Ssunil m_get_string(&m, &username);
10706405042Ssunil m_get_mailaddr(&m, &maddr);
10806405042Ssunil m_end(&m);
10906405042Ssunil
11006405042Ssunil ret = lka_mailaddrmap(tablename, username, &maddr);
11106405042Ssunil
11206405042Ssunil m_create(p, IMSG_SMTP_CHECK_SENDER, 0, 0, -1);
11306405042Ssunil m_add_id(p, reqid);
11406405042Ssunil m_add_int(p, ret);
11506405042Ssunil m_close(p);
11606405042Ssunil return;
11706405042Ssunil
118aa1d5973Seric case IMSG_SMTP_EXPAND_RCPT:
11965c4fdfbSgilles m_msg(&m, imsg);
12065c4fdfbSgilles m_get_id(&m, &reqid);
12165c4fdfbSgilles m_get_envelope(&m, &evp);
12265c4fdfbSgilles m_end(&m);
12365c4fdfbSgilles lka_session(reqid, &evp);
124e5b07014Sgilles return;
125e5b07014Sgilles
126aa1d5973Seric case IMSG_SMTP_LOOKUP_HELO:
127cc81b7c6Seric m_msg(&m, imsg);
128cc81b7c6Seric m_get_id(&m, &reqid);
129cc81b7c6Seric m_get_string(&m, &tablename);
130cc81b7c6Seric m_get_sockaddr(&m, (struct sockaddr *)&ss);
131cc81b7c6Seric m_end(&m);
132cc81b7c6Seric
133cc81b7c6Seric ret = lka_addrname(tablename, (struct sockaddr*)&ss,
134cc81b7c6Seric &addrname);
135cc81b7c6Seric
136aa1d5973Seric m_create(p, IMSG_SMTP_LOOKUP_HELO, 0, 0, -1);
137cc81b7c6Seric m_add_id(p, reqid);
138cc81b7c6Seric m_add_int(p, ret);
139cc81b7c6Seric if (ret == LKA_OK)
140cc81b7c6Seric m_add_string(p, addrname.name);
141cc81b7c6Seric m_close(p);
142cc81b7c6Seric return;
143cc81b7c6Seric
144aa1d5973Seric case IMSG_SMTP_AUTHENTICATE:
14565c4fdfbSgilles m_msg(&m, imsg);
14665c4fdfbSgilles m_get_id(&m, &reqid);
14765c4fdfbSgilles m_get_string(&m, &tablename);
14865c4fdfbSgilles m_get_string(&m, &username);
14965c4fdfbSgilles m_get_string(&m, &password);
15065c4fdfbSgilles m_end(&m);
15165c4fdfbSgilles
15265c4fdfbSgilles if (!tablename[0]) {
15365c4fdfbSgilles m_create(p_parent, IMSG_LKA_AUTHENTICATE,
154299c4efeSeric 0, 0, -1);
15565c4fdfbSgilles m_add_id(p_parent, reqid);
15665c4fdfbSgilles m_add_string(p_parent, username);
15765c4fdfbSgilles m_add_string(p_parent, password);
15865c4fdfbSgilles m_close(p_parent);
15965c4fdfbSgilles return;
16065c4fdfbSgilles }
16165c4fdfbSgilles
16265c4fdfbSgilles ret = lka_authenticate(tablename, username, password);
16365c4fdfbSgilles
16487ca757cSeric m_create(p, IMSG_SMTP_AUTHENTICATE, 0, 0, -1);
16565c4fdfbSgilles m_add_id(p, reqid);
16665c4fdfbSgilles m_add_int(p, ret);
16765c4fdfbSgilles m_close(p);
168ed1929b6Sjacekm return;
169ed1929b6Sjacekm
170aa1d5973Seric case IMSG_MDA_LOOKUP_USERINFO:
17165c4fdfbSgilles m_msg(&m, imsg);
1727eed50e8Seric m_get_id(&m, &reqid);
17365c4fdfbSgilles m_get_string(&m, &tablename);
17465c4fdfbSgilles m_get_string(&m, &username);
17565c4fdfbSgilles m_end(&m);
176831779c9Sgilles
17765c4fdfbSgilles ret = lka_userinfo(tablename, username, &userinfo);
17865c4fdfbSgilles
179aa1d5973Seric m_create(p, IMSG_MDA_LOOKUP_USERINFO, 0, 0, -1);
1807eed50e8Seric m_add_id(p, reqid);
18165c4fdfbSgilles m_add_int(p, ret);
18265c4fdfbSgilles if (ret == LKA_OK)
18365c4fdfbSgilles m_add_data(p, &userinfo, sizeof(userinfo));
18465c4fdfbSgilles m_close(p);
185ed1929b6Sjacekm return;
18665c4fdfbSgilles
187aa1d5973Seric case IMSG_MTA_LOOKUP_CREDENTIALS:
18865c4fdfbSgilles m_msg(&m, imsg);
18965c4fdfbSgilles m_get_id(&m, &reqid);
19065c4fdfbSgilles m_get_string(&m, &tablename);
19165c4fdfbSgilles m_get_string(&m, &label);
19265c4fdfbSgilles m_end(&m);
19365c4fdfbSgilles
19465c4fdfbSgilles lka_credentials(tablename, label, buf, sizeof(buf));
19565c4fdfbSgilles
196aa1d5973Seric m_create(p, IMSG_MTA_LOOKUP_CREDENTIALS, 0, 0, -1);
19765c4fdfbSgilles m_add_id(p, reqid);
19865c4fdfbSgilles m_add_string(p, buf);
19965c4fdfbSgilles m_close(p);
20065c4fdfbSgilles return;
20165c4fdfbSgilles
202aa1d5973Seric case IMSG_MTA_LOOKUP_SOURCE:
20365c4fdfbSgilles m_msg(&m, imsg);
20465c4fdfbSgilles m_get_id(&m, &reqid);
20565c4fdfbSgilles m_get_string(&m, &tablename);
20686892768Seric m_end(&m);
20765c4fdfbSgilles
208ff18143eSeric table = table_find(env, tablename);
20965c4fdfbSgilles
210aa1d5973Seric m_create(p, IMSG_MTA_LOOKUP_SOURCE, 0, 0, -1);
21165c4fdfbSgilles m_add_id(p, reqid);
21265c4fdfbSgilles
21365c4fdfbSgilles if (table == NULL) {
21465c4fdfbSgilles log_warn("warn: source address table %s missing",
21565c4fdfbSgilles tablename);
21665c4fdfbSgilles m_add_int(p, LKA_TEMPFAIL);
21765c4fdfbSgilles }
21865c4fdfbSgilles else {
219699c3f98Seric ret = table_fetch(table, K_SOURCE, &lk);
22065c4fdfbSgilles if (ret == -1)
22165c4fdfbSgilles m_add_int(p, LKA_TEMPFAIL);
22265c4fdfbSgilles else if (ret == 0)
22365c4fdfbSgilles m_add_int(p, LKA_PERMFAIL);
22465c4fdfbSgilles else {
2254809a514Sgilles m_add_int(p, LKA_OK);
226299c4efeSeric m_add_sockaddr(p,
227299c4efeSeric (struct sockaddr *)&lk.source.addr);
2284809a514Sgilles }
22965c4fdfbSgilles }
23065c4fdfbSgilles m_close(p);
23165c4fdfbSgilles return;
23265c4fdfbSgilles
233aa1d5973Seric case IMSG_MTA_LOOKUP_HELO:
23465c4fdfbSgilles m_msg(&m, imsg);
23565c4fdfbSgilles m_get_id(&m, &reqid);
23665c4fdfbSgilles m_get_string(&m, &tablename);
23765c4fdfbSgilles m_get_sockaddr(&m, (struct sockaddr *)&ss);
23865c4fdfbSgilles m_end(&m);
23965c4fdfbSgilles
24065c4fdfbSgilles ret = lka_addrname(tablename, (struct sockaddr*)&ss,
24165c4fdfbSgilles &addrname);
24265c4fdfbSgilles
243aa1d5973Seric m_create(p, IMSG_MTA_LOOKUP_HELO, 0, 0, -1);
24465c4fdfbSgilles m_add_id(p, reqid);
24565c4fdfbSgilles m_add_int(p, ret);
24665c4fdfbSgilles if (ret == LKA_OK)
24765c4fdfbSgilles m_add_string(p, addrname.name);
24865c4fdfbSgilles m_close(p);
24965c4fdfbSgilles return;
25065c4fdfbSgilles
251a8e22235Sgilles case IMSG_MTA_LOOKUP_SMARTHOST:
252a8e22235Sgilles m_msg(&m, imsg);
253a8e22235Sgilles m_get_id(&m, &reqid);
2549e7c83d3Sgilles m_get_string(&m, &domain);
255a8e22235Sgilles m_get_string(&m, &tablename);
256a8e22235Sgilles m_end(&m);
257a8e22235Sgilles
258ff18143eSeric table = table_find(env, tablename);
259a8e22235Sgilles
260a8e22235Sgilles m_create(p, IMSG_MTA_LOOKUP_SMARTHOST, 0, 0, -1);
261a8e22235Sgilles m_add_id(p, reqid);
262a8e22235Sgilles
263a8e22235Sgilles if (table == NULL) {
264a8e22235Sgilles log_warn("warn: smarthost table %s missing", tablename);
265a8e22235Sgilles m_add_int(p, LKA_TEMPFAIL);
266a8e22235Sgilles }
267a8e22235Sgilles else {
2689e7c83d3Sgilles if (domain == NULL)
269699c3f98Seric ret = table_fetch(table, K_RELAYHOST, &lk);
2709e7c83d3Sgilles else
2719e7c83d3Sgilles ret = table_lookup(table, K_RELAYHOST, domain, &lk);
2729e7c83d3Sgilles
273a8e22235Sgilles if (ret == -1)
274a8e22235Sgilles m_add_int(p, LKA_TEMPFAIL);
275a8e22235Sgilles else if (ret == 0)
276a8e22235Sgilles m_add_int(p, LKA_PERMFAIL);
277a8e22235Sgilles else {
278a8e22235Sgilles m_add_int(p, LKA_OK);
2798f342d13Seric m_add_string(p, lk.relayhost);
280a8e22235Sgilles }
281a8e22235Sgilles }
282a8e22235Sgilles m_close(p);
283a8e22235Sgilles return;
284a8e22235Sgilles
285ed1929b6Sjacekm case IMSG_CONF_START:
286ed1929b6Sjacekm return;
287ed1929b6Sjacekm
288ed1929b6Sjacekm case IMSG_CONF_END:
289f24248b7Sreyk if (tracing & TRACE_TABLES)
290b80b41afSgilles table_dump_all(env);
291b9b187cbSgilles
292b9b187cbSgilles /* fork & exec tables that need it */
293b80b41afSgilles table_open_all(env);
294e9ab1c57Seric
295b9b187cbSgilles /* revoke proc & exec */
296590a6142Sgilles if (pledge("stdio rpath inet dns getpw recvfd sendfd",
297b9b187cbSgilles NULL) == -1)
298ff01b044Seric fatal("pledge");
299b9b187cbSgilles
300ec69ed85Sgilles /* setup proc registering task */
301ec69ed85Sgilles evtimer_set(&ev_proc_ready, proc_timeout, &ev_proc_ready);
302ec69ed85Sgilles tv.tv_sec = 0;
303ec69ed85Sgilles tv.tv_usec = 10;
304ec69ed85Sgilles evtimer_add(&ev_proc_ready, &tv);
305ed1929b6Sjacekm return;
306ed1929b6Sjacekm
30757d312f7Seric case IMSG_LKA_OPEN_FORWARD:
308510586acSclaudio lka_session_forward_reply(imsg->data, imsg_get_fd(imsg));
30957d312f7Seric return;
31057d312f7Seric
31157d312f7Seric case IMSG_LKA_AUTHENTICATE:
31257d312f7Seric imsg->hdr.type = IMSG_SMTP_AUTHENTICATE;
3131a5b831aSmartijn m_forward(p_dispatcher, imsg);
31457d312f7Seric return;
31557d312f7Seric
316ed1929b6Sjacekm case IMSG_CTL_VERBOSE:
31765c4fdfbSgilles m_msg(&m, imsg);
31865c4fdfbSgilles m_get_int(&m, &v);
31965c4fdfbSgilles m_end(&m);
320f24248b7Sreyk log_trace_verbose(v);
32165c4fdfbSgilles return;
32265c4fdfbSgilles
32365c4fdfbSgilles case IMSG_CTL_PROFILE:
32465c4fdfbSgilles m_msg(&m, imsg);
32565c4fdfbSgilles m_get_int(&m, &v);
32665c4fdfbSgilles m_end(&m);
32765c4fdfbSgilles profiling = v;
328ed1929b6Sjacekm return;
3295ff81a3dSgilles
330aa1d5973Seric case IMSG_CTL_UPDATE_TABLE:
331bbe9c651Ssunil ret = 0;
332ff18143eSeric table = table_find(env, imsg->data);
33365c4fdfbSgilles if (table == NULL) {
33465c4fdfbSgilles log_warnx("warn: Lookup table not found: "
33565c4fdfbSgilles "\"%s\"", (char *)imsg->data);
336bbe9c651Ssunil } else
337bbe9c651Ssunil ret = table_update(table);
338bbe9c651Ssunil
339bbe9c651Ssunil m_compose(p_control,
340bbe9c651Ssunil (ret == 1) ? IMSG_CTL_OK : IMSG_CTL_FAIL,
341bbe9c651Ssunil imsg->hdr.peerid, 0, -1, NULL, 0);
342e9283ba6Sgilles return;
343a93e09f5Sgilles
344a93e09f5Sgilles case IMSG_LKA_PROCESSOR_FORK:
345a93e09f5Sgilles m_msg(&m, imsg);
346a93e09f5Sgilles m_get_string(&m, &procname);
34726bbc7b9Sgilles m_get_u32(&m, &subsystems);
348a93e09f5Sgilles m_end(&m);
349a93e09f5Sgilles
350dbc3cea0Smartijn m_create(p, IMSG_LKA_PROCESSOR_ERRFD, 0, 0, -1);
351dbc3cea0Smartijn m_add_string(p, procname);
352dbc3cea0Smartijn m_close(p);
353dbc3cea0Smartijn
354510586acSclaudio lka_proc_forked(procname, subsystems, imsg_get_fd(imsg));
355a93e09f5Sgilles return;
356a93e09f5Sgilles
357dbc3cea0Smartijn case IMSG_LKA_PROCESSOR_ERRFD:
358dbc3cea0Smartijn m_msg(&m, imsg);
359dbc3cea0Smartijn m_get_string(&m, &procname);
360dbc3cea0Smartijn m_end(&m);
361dbc3cea0Smartijn
362510586acSclaudio fd = imsg_get_fd(imsg);
363510586acSclaudio lka_proc_errfd(procname, fd);
364510586acSclaudio shutdown(fd, SHUT_WR);
365dbc3cea0Smartijn return;
366ff05ba49Sgilles
367d738de61Sgilles case IMSG_REPORT_SMTP_LINK_CONNECT:
368ff05ba49Sgilles m_msg(&m, imsg);
369d738de61Sgilles m_get_string(&m, &direction);
3704e92310aSgilles m_get_timeval(&m, &tv);
371ff05ba49Sgilles m_get_id(&m, &reqid);
3722a5af9afSgilles m_get_string(&m, &rdns);
3737bbc0d03Sgilles m_get_int(&m, &fcrdns);
374b7d8690dSgilles m_get_sockaddr(&m, (struct sockaddr *)&ss_src);
375b7d8690dSgilles m_get_sockaddr(&m, (struct sockaddr *)&ss_dest);
376ff05ba49Sgilles m_end(&m);
377ff05ba49Sgilles
3784e92310aSgilles lka_report_smtp_link_connect(direction, &tv, reqid, rdns, fcrdns, &ss_src, &ss_dest);
379ff05ba49Sgilles return;
380ff05ba49Sgilles
381233a267cSmartijn case IMSG_REPORT_SMTP_LINK_GREETING:
382233a267cSmartijn m_msg(&m, imsg);
383233a267cSmartijn m_get_string(&m, &direction);
384233a267cSmartijn m_get_timeval(&m, &tv);
385233a267cSmartijn m_get_id(&m, &reqid);
386233a267cSmartijn m_get_string(&m, &domain);
387233a267cSmartijn m_end(&m);
388233a267cSmartijn
389233a267cSmartijn lka_report_smtp_link_greeting(direction, reqid, &tv, domain);
390233a267cSmartijn return;
391233a267cSmartijn
392d738de61Sgilles case IMSG_REPORT_SMTP_LINK_DISCONNECT:
393ff05ba49Sgilles m_msg(&m, imsg);
394d738de61Sgilles m_get_string(&m, &direction);
3954e92310aSgilles m_get_timeval(&m, &tv);
396ff05ba49Sgilles m_get_id(&m, &reqid);
397ff05ba49Sgilles m_end(&m);
398ff05ba49Sgilles
3994e92310aSgilles lka_report_smtp_link_disconnect(direction, &tv, reqid);
400ff05ba49Sgilles return;
401ff05ba49Sgilles
402d738de61Sgilles case IMSG_REPORT_SMTP_LINK_IDENTIFY:
4037ec3fc38Sgilles m_msg(&m, imsg);
404d738de61Sgilles m_get_string(&m, &direction);
4054e92310aSgilles m_get_timeval(&m, &tv);
4067ec3fc38Sgilles m_get_id(&m, &reqid);
407f9257e33Sgilles m_get_string(&m, &helomethod);
4087ec3fc38Sgilles m_get_string(&m, &heloname);
4097ec3fc38Sgilles m_end(&m);
4107ec3fc38Sgilles
411f9257e33Sgilles lka_report_smtp_link_identify(direction, &tv, reqid, helomethod, heloname);
4127ec3fc38Sgilles return;
4137ec3fc38Sgilles
414d738de61Sgilles case IMSG_REPORT_SMTP_LINK_TLS:
415ff05ba49Sgilles m_msg(&m, imsg);
416d738de61Sgilles m_get_string(&m, &direction);
4174e92310aSgilles m_get_timeval(&m, &tv);
418ff05ba49Sgilles m_get_id(&m, &reqid);
419ff05ba49Sgilles m_get_string(&m, &ciphers);
420ff05ba49Sgilles m_end(&m);
421ff05ba49Sgilles
4224e92310aSgilles lka_report_smtp_link_tls(direction, &tv, reqid, ciphers);
423ff05ba49Sgilles return;
424ff05ba49Sgilles
425a742ecdcSgilles case IMSG_REPORT_SMTP_LINK_AUTH:
426a742ecdcSgilles m_msg(&m, imsg);
427a742ecdcSgilles m_get_string(&m, &direction);
428a742ecdcSgilles m_get_timeval(&m, &tv);
429a742ecdcSgilles m_get_id(&m, &reqid);
430a742ecdcSgilles m_get_string(&m, &username);
431a742ecdcSgilles m_get_string(&m, &result);
432a742ecdcSgilles m_end(&m);
433a742ecdcSgilles
434a742ecdcSgilles lka_report_smtp_link_auth(direction, &tv, reqid, username, result);
435a742ecdcSgilles return;
436a742ecdcSgilles
437ea76d14bSgilles case IMSG_REPORT_SMTP_TX_RESET:
438ea76d14bSgilles m_msg(&m, imsg);
439ea76d14bSgilles m_get_string(&m, &direction);
440ea76d14bSgilles m_get_timeval(&m, &tv);
441ea76d14bSgilles m_get_id(&m, &reqid);
442ea76d14bSgilles m_get_u32(&m, &msgid);
443ea76d14bSgilles m_end(&m);
444ea76d14bSgilles
445ea76d14bSgilles lka_report_smtp_tx_reset(direction, &tv, reqid, msgid);
446ea76d14bSgilles return;
447ea76d14bSgilles
448d738de61Sgilles case IMSG_REPORT_SMTP_TX_BEGIN:
449ff05ba49Sgilles m_msg(&m, imsg);
450d738de61Sgilles m_get_string(&m, &direction);
4514e92310aSgilles m_get_timeval(&m, &tv);
452ff05ba49Sgilles m_get_id(&m, &reqid);
45371b9078fSgilles m_get_u32(&m, &msgid);
454ff05ba49Sgilles m_end(&m);
455ff05ba49Sgilles
4564e92310aSgilles lka_report_smtp_tx_begin(direction, &tv, reqid, msgid);
45771b9078fSgilles return;
45871b9078fSgilles
459d738de61Sgilles case IMSG_REPORT_SMTP_TX_MAIL:
4607929fb13Sgilles m_msg(&m, imsg);
461d738de61Sgilles m_get_string(&m, &direction);
4624e92310aSgilles m_get_timeval(&m, &tv);
4637929fb13Sgilles m_get_id(&m, &reqid);
4647929fb13Sgilles m_get_u32(&m, &msgid);
4657929fb13Sgilles m_get_string(&m, &address);
4667929fb13Sgilles m_get_int(&m, &ok);
4677929fb13Sgilles m_end(&m);
4687929fb13Sgilles
4694e92310aSgilles lka_report_smtp_tx_mail(direction, &tv, reqid, msgid, address, ok);
4707929fb13Sgilles return;
4717929fb13Sgilles
472d738de61Sgilles case IMSG_REPORT_SMTP_TX_RCPT:
4737929fb13Sgilles m_msg(&m, imsg);
474d738de61Sgilles m_get_string(&m, &direction);
4754e92310aSgilles m_get_timeval(&m, &tv);
4767929fb13Sgilles m_get_id(&m, &reqid);
4777929fb13Sgilles m_get_u32(&m, &msgid);
4787929fb13Sgilles m_get_string(&m, &address);
4797929fb13Sgilles m_get_int(&m, &ok);
4807929fb13Sgilles m_end(&m);
4817929fb13Sgilles
4824e92310aSgilles lka_report_smtp_tx_rcpt(direction, &tv, reqid, msgid, address, ok);
4837929fb13Sgilles return;
4847929fb13Sgilles
485d738de61Sgilles case IMSG_REPORT_SMTP_TX_ENVELOPE:
48671b9078fSgilles m_msg(&m, imsg);
487d738de61Sgilles m_get_string(&m, &direction);
4884e92310aSgilles m_get_timeval(&m, &tv);
48971b9078fSgilles m_get_id(&m, &reqid);
49071b9078fSgilles m_get_u32(&m, &msgid);
49171b9078fSgilles m_get_id(&m, &evpid);
49271b9078fSgilles m_end(&m);
49371b9078fSgilles
4944e92310aSgilles lka_report_smtp_tx_envelope(direction, &tv, reqid, msgid, evpid);
495ff05ba49Sgilles return;
496ff05ba49Sgilles
497e7d82dd0Sgilles case IMSG_REPORT_SMTP_TX_DATA:
498e7d82dd0Sgilles m_msg(&m, imsg);
499e7d82dd0Sgilles m_get_string(&m, &direction);
5004e92310aSgilles m_get_timeval(&m, &tv);
501e7d82dd0Sgilles m_get_id(&m, &reqid);
502e7d82dd0Sgilles m_get_u32(&m, &msgid);
503e7d82dd0Sgilles m_get_int(&m, &ok);
504e7d82dd0Sgilles m_end(&m);
505e7d82dd0Sgilles
5064e92310aSgilles lka_report_smtp_tx_data(direction, &tv, reqid, msgid, ok);
507e7d82dd0Sgilles return;
508e7d82dd0Sgilles
509d738de61Sgilles case IMSG_REPORT_SMTP_TX_COMMIT:
510ff05ba49Sgilles m_msg(&m, imsg);
511d738de61Sgilles m_get_string(&m, &direction);
5124e92310aSgilles m_get_timeval(&m, &tv);
513ff05ba49Sgilles m_get_id(&m, &reqid);
51471b9078fSgilles m_get_u32(&m, &msgid);
51571b9078fSgilles m_get_size(&m, &msgsz);
516ff05ba49Sgilles m_end(&m);
517ff05ba49Sgilles
5184e92310aSgilles lka_report_smtp_tx_commit(direction, &tv, reqid, msgid, msgsz);
519ff05ba49Sgilles return;
520ff05ba49Sgilles
521d738de61Sgilles case IMSG_REPORT_SMTP_TX_ROLLBACK:
522ff05ba49Sgilles m_msg(&m, imsg);
523d738de61Sgilles m_get_string(&m, &direction);
5244e92310aSgilles m_get_timeval(&m, &tv);
525ff05ba49Sgilles m_get_id(&m, &reqid);
526b6b294a3Sgilles m_get_u32(&m, &msgid);
527ff05ba49Sgilles m_end(&m);
528ff05ba49Sgilles
5294e92310aSgilles lka_report_smtp_tx_rollback(direction, &tv, reqid, msgid);
530ff05ba49Sgilles return;
531ff05ba49Sgilles
532d738de61Sgilles case IMSG_REPORT_SMTP_PROTOCOL_CLIENT:
533ff05ba49Sgilles m_msg(&m, imsg);
534d738de61Sgilles m_get_string(&m, &direction);
5354e92310aSgilles m_get_timeval(&m, &tv);
536ff05ba49Sgilles m_get_id(&m, &reqid);
537ff05ba49Sgilles m_get_string(&m, &command);
538ff05ba49Sgilles m_end(&m);
539ff05ba49Sgilles
5404e92310aSgilles lka_report_smtp_protocol_client(direction, &tv, reqid, command);
541ff05ba49Sgilles return;
542ff05ba49Sgilles
543d738de61Sgilles case IMSG_REPORT_SMTP_PROTOCOL_SERVER:
544ff05ba49Sgilles m_msg(&m, imsg);
545d738de61Sgilles m_get_string(&m, &direction);
5464e92310aSgilles m_get_timeval(&m, &tv);
547ff05ba49Sgilles m_get_id(&m, &reqid);
548ff05ba49Sgilles m_get_string(&m, &response);
549ff05ba49Sgilles m_end(&m);
550ff05ba49Sgilles
5514e92310aSgilles lka_report_smtp_protocol_server(direction, &tv, reqid, response);
552ff05ba49Sgilles return;
553d7b0dc3bSgilles
554d738de61Sgilles case IMSG_REPORT_SMTP_FILTER_RESPONSE:
555b0d3076dSgilles m_msg(&m, imsg);
556d738de61Sgilles m_get_string(&m, &direction);
5574e92310aSgilles m_get_timeval(&m, &tv);
558b0d3076dSgilles m_get_id(&m, &reqid);
559b0d3076dSgilles m_get_int(&m, &filter_phase);
560b0d3076dSgilles m_get_int(&m, &filter_response);
561b0d3076dSgilles m_get_string(&m, &filter_param);
562b0d3076dSgilles m_end(&m);
563b0d3076dSgilles
5644e92310aSgilles lka_report_smtp_filter_response(direction, &tv, reqid,
565b0d3076dSgilles filter_phase, filter_response, filter_param);
566b0d3076dSgilles return;
567b0d3076dSgilles
568760deba3Sgilles case IMSG_REPORT_SMTP_TIMEOUT:
569760deba3Sgilles m_msg(&m, imsg);
570760deba3Sgilles m_get_string(&m, &direction);
571760deba3Sgilles m_get_timeval(&m, &tv);
572760deba3Sgilles m_get_id(&m, &reqid);
573760deba3Sgilles m_end(&m);
574760deba3Sgilles
575760deba3Sgilles lka_report_smtp_timeout(direction, &tv, reqid);
576760deba3Sgilles return;
577b6b294a3Sgilles
5782b1a70ccSgilles case IMSG_FILTER_SMTP_PROTOCOL:
579d7b0dc3bSgilles m_msg(&m, imsg);
580d7b0dc3bSgilles m_get_id(&m, &reqid);
581d7b0dc3bSgilles m_get_int(&m, &filter_phase);
582d7b0dc3bSgilles m_get_string(&m, &filter_param);
583d7b0dc3bSgilles m_end(&m);
584d7b0dc3bSgilles
58571507431Sgilles lka_filter_protocol(reqid, filter_phase, filter_param);
586d7b0dc3bSgilles return;
587590a6142Sgilles
5882b1a70ccSgilles case IMSG_FILTER_SMTP_BEGIN:
589590a6142Sgilles m_msg(&m, imsg);
590590a6142Sgilles m_get_id(&m, &reqid);
591ec69ed85Sgilles m_get_string(&m, &filter_name);
592590a6142Sgilles m_end(&m);
593590a6142Sgilles
5946c0f0c33Sgilles lka_filter_begin(reqid, filter_name);
595590a6142Sgilles return;
596590a6142Sgilles
5972b1a70ccSgilles case IMSG_FILTER_SMTP_END:
598590a6142Sgilles m_msg(&m, imsg);
599590a6142Sgilles m_get_id(&m, &reqid);
600590a6142Sgilles m_end(&m);
601590a6142Sgilles
602590a6142Sgilles lka_filter_end(reqid);
603590a6142Sgilles return;
604590a6142Sgilles
6052b1a70ccSgilles case IMSG_FILTER_SMTP_DATA_BEGIN:
606590a6142Sgilles m_msg(&m, imsg);
607590a6142Sgilles m_get_id(&m, &reqid);
608590a6142Sgilles m_end(&m);
609590a6142Sgilles
610590a6142Sgilles lka_filter_data_begin(reqid);
611590a6142Sgilles return;
612590a6142Sgilles
6132b1a70ccSgilles case IMSG_FILTER_SMTP_DATA_END:
614590a6142Sgilles m_msg(&m, imsg);
615590a6142Sgilles m_get_id(&m, &reqid);
616590a6142Sgilles m_end(&m);
617590a6142Sgilles
618590a6142Sgilles lka_filter_data_end(reqid);
619590a6142Sgilles return;
620590a6142Sgilles
621e9283ba6Sgilles }
622e9283ba6Sgilles
623ff01b044Seric fatalx("lka_imsg: unexpected %s imsg", imsg_to_str(imsg->hdr.type));
624ed1929b6Sjacekm }
625ed1929b6Sjacekm
626be925435Sgilles static void
lka_sig_handler(int sig,short event,void * p)6273ef9cbf7Sgilles lka_sig_handler(int sig, short event, void *p)
6283ef9cbf7Sgilles {
62997c17d55Sjacekm int status;
63097c17d55Sjacekm pid_t pid;
63197c17d55Sjacekm
6323ef9cbf7Sgilles switch (sig) {
63397c17d55Sjacekm case SIGCHLD:
63497c17d55Sjacekm do {
63597c17d55Sjacekm pid = waitpid(-1, &status, WNOHANG);
63697c17d55Sjacekm } while (pid > 0 || (pid == -1 && errno == EINTR));
63797c17d55Sjacekm break;
6383ef9cbf7Sgilles default:
6393ef9cbf7Sgilles fatalx("lka_sig_handler: unexpected signal");
6403ef9cbf7Sgilles }
6413ef9cbf7Sgilles }
6423ef9cbf7Sgilles
6433ef9cbf7Sgilles void
lka_shutdown(void)6443ef9cbf7Sgilles lka_shutdown(void)
6453ef9cbf7Sgilles {
64643962b9cSeric log_debug("debug: lookup agent exiting");
6473ef9cbf7Sgilles _exit(0);
6483ef9cbf7Sgilles }
6493ef9cbf7Sgilles
650b88ab68dSeric int
lka(void)651e4d36f12Seric lka(void)
6523ef9cbf7Sgilles {
6533ef9cbf7Sgilles struct passwd *pw;
65497c17d55Sjacekm struct event ev_sigchld;
6553ef9cbf7Sgilles
6561c3ac238Seric purge_config(PURGE_LISTENERS);
6573ef9cbf7Sgilles
65811d04e02Seric if ((pw = getpwnam(SMTPD_USER)) == NULL)
65911d04e02Seric fatalx("unknown user " SMTPD_USER);
6603ef9cbf7Sgilles
66165c4fdfbSgilles config_process(PROC_LKA);
6623ef9cbf7Sgilles
663009a3f47Sgilles if (initgroups(pw->pw_name, pw->pw_gid) ||
6643ef9cbf7Sgilles setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
6653ef9cbf7Sgilles setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
6663ef9cbf7Sgilles fatal("lka: cannot drop privileges");
6673ef9cbf7Sgilles
668ed1929b6Sjacekm imsg_callback = lka_imsg;
6693ef9cbf7Sgilles event_init();
6703ef9cbf7Sgilles
671e4d36f12Seric signal_set(&ev_sigchld, SIGCHLD, lka_sig_handler, NULL);
67297c17d55Sjacekm signal_add(&ev_sigchld, NULL);
67343962b9cSeric signal(SIGINT, SIG_IGN);
67443962b9cSeric signal(SIGTERM, SIG_IGN);
6753ef9cbf7Sgilles signal(SIGPIPE, SIG_IGN);
6763ef9cbf7Sgilles signal(SIGHUP, SIG_IGN);
6773ef9cbf7Sgilles
67865c4fdfbSgilles config_peer(PROC_PARENT);
67965c4fdfbSgilles config_peer(PROC_QUEUE);
68065c4fdfbSgilles config_peer(PROC_CONTROL);
6811a5b831aSmartijn config_peer(PROC_DISPATCHER);
6823ef9cbf7Sgilles
68365c4fdfbSgilles /* Ignore them until we get our config */
6841a5b831aSmartijn mproc_disable(p_dispatcher);
685e9ab1c57Seric
686ec69ed85Sgilles lka_report_init();
687ec69ed85Sgilles lka_filter_init();
688ec69ed85Sgilles
689b9b187cbSgilles /* proc & exec will be revoked before serving requests */
690590a6142Sgilles if (pledge("stdio rpath inet dns getpw recvfd sendfd proc exec", NULL) == -1)
691ff01b044Seric fatal("pledge");
692a8c16586Sgilles
693f94528c3Seric event_dispatch();
694f94528c3Seric fatalx("exited event loop");
6953ef9cbf7Sgilles
6963ef9cbf7Sgilles return (0);
6973ef9cbf7Sgilles }
6983ef9cbf7Sgilles
699ec69ed85Sgilles static void
proc_timeout(int fd,short event,void * p)700ec69ed85Sgilles proc_timeout(int fd, short event, void *p)
701ec69ed85Sgilles {
702ec69ed85Sgilles struct event *ev = p;
703ec69ed85Sgilles struct timeval tv;
704ec69ed85Sgilles
705ec69ed85Sgilles if (!lka_proc_ready())
706ec69ed85Sgilles goto reset;
707ec69ed85Sgilles
708ec69ed85Sgilles lka_filter_ready();
7091a5b831aSmartijn mproc_enable(p_dispatcher);
710ec69ed85Sgilles return;
711ec69ed85Sgilles
712ec69ed85Sgilles reset:
713ec69ed85Sgilles tv.tv_sec = 0;
714ec69ed85Sgilles tv.tv_usec = 10;
715ec69ed85Sgilles evtimer_add(ev, &tv);
716ec69ed85Sgilles }
717ec69ed85Sgilles
718ec69ed85Sgilles
71923819f34Seric static int
lka_authenticate(const char * tablename,const char * user,const char * password)72065c4fdfbSgilles lka_authenticate(const char *tablename, const char *user, const char *password)
7213ef9cbf7Sgilles {
72265c4fdfbSgilles struct table *table;
72347388f99Sgilles char offloadkey[LINE_MAX];
724299c4efeSeric union lookup lk;
72565c4fdfbSgilles
726299c4efeSeric log_debug("debug: lka: authenticating for %s:%s", tablename, user);
727ff18143eSeric table = table_find(env, tablename);
72865c4fdfbSgilles if (table == NULL) {
72965c4fdfbSgilles log_warnx("warn: could not find table %s needed for authentication",
73065c4fdfbSgilles tablename);
73165c4fdfbSgilles return (LKA_TEMPFAIL);
73265c4fdfbSgilles }
73365c4fdfbSgilles
73447388f99Sgilles /* table backend supports authentication offloading */
73547388f99Sgilles if (table_check_service(table, K_AUTH)) {
73647388f99Sgilles if (!bsnprintf(offloadkey, sizeof(offloadkey), "%s:%s",
73747388f99Sgilles user, password)) {
73847388f99Sgilles log_warnx("warn: key serialization failed for %s:%s",
73947388f99Sgilles tablename, user);
74047388f99Sgilles return (LKA_TEMPFAIL);
74147388f99Sgilles }
74247388f99Sgilles switch (table_match(table, K_AUTH, offloadkey)) {
74347388f99Sgilles case -1:
74447388f99Sgilles log_warnx("warn: user credentials lookup fail for %s:%s",
74547388f99Sgilles tablename, user);
74647388f99Sgilles return (LKA_TEMPFAIL);
74747388f99Sgilles case 0:
74847388f99Sgilles return (LKA_PERMFAIL);
74947388f99Sgilles default:
75047388f99Sgilles return (LKA_OK);
75147388f99Sgilles }
75247388f99Sgilles }
75347388f99Sgilles
75493cc0b04Seric switch (table_lookup(table, K_CREDENTIALS, user, &lk)) {
75565c4fdfbSgilles case -1:
75665c4fdfbSgilles log_warnx("warn: user credentials lookup fail for %s:%s",
75765c4fdfbSgilles tablename, user);
75865c4fdfbSgilles return (LKA_TEMPFAIL);
75965c4fdfbSgilles case 0:
76065c4fdfbSgilles return (LKA_PERMFAIL);
76165c4fdfbSgilles default:
762e7d7d40dSsunil if (crypt_checkpass(password, lk.creds.password) == 0)
76365c4fdfbSgilles return (LKA_OK);
76465c4fdfbSgilles return (LKA_PERMFAIL);
76565c4fdfbSgilles }
7663ef9cbf7Sgilles }
7673ef9cbf7Sgilles
768be925435Sgilles static int
lka_credentials(const char * tablename,const char * label,char * dst,size_t sz)76965c4fdfbSgilles lka_credentials(const char *tablename, const char *label, char *dst, size_t sz)
770df982ec9Sgilles {
77165c4fdfbSgilles struct table *table;
772299c4efeSeric union lookup lk;
773e5b07014Sgilles char *buf;
77465c4fdfbSgilles int buflen, r;
775df982ec9Sgilles
776ff18143eSeric table = table_find(env, tablename);
77765c4fdfbSgilles if (table == NULL) {
77865c4fdfbSgilles log_warnx("warn: credentials table %s missing", tablename);
77965c4fdfbSgilles return (LKA_TEMPFAIL);
780e5b07014Sgilles }
781e5b07014Sgilles
78265c4fdfbSgilles dst[0] = '\0';
78365c4fdfbSgilles
78493cc0b04Seric switch (table_lookup(table, K_CREDENTIALS, label, &lk)) {
78565c4fdfbSgilles case -1:
78665c4fdfbSgilles log_warnx("warn: credentials lookup fail for %s:%s",
78765c4fdfbSgilles tablename, label);
78865c4fdfbSgilles return (LKA_TEMPFAIL);
78965c4fdfbSgilles case 0:
79065c4fdfbSgilles log_warnx("warn: credentials not found for %s:%s",
79165c4fdfbSgilles tablename, label);
79265c4fdfbSgilles return (LKA_PERMFAIL);
79365c4fdfbSgilles default:
79465c4fdfbSgilles if ((buflen = asprintf(&buf, "%c%s%c%s", '\0',
795299c4efeSeric lk.creds.username, '\0', lk.creds.password)) == -1) {
79665c4fdfbSgilles log_warn("warn");
79765c4fdfbSgilles return (LKA_TEMPFAIL);
79865c4fdfbSgilles }
79965c4fdfbSgilles
800254aed36Seric r = base64_encode((unsigned char *)buf, buflen, dst, sz);
801e5b07014Sgilles free(buf);
80265c4fdfbSgilles
80365c4fdfbSgilles if (r == -1) {
80465c4fdfbSgilles log_warnx("warn: credentials parse error for %s:%s",
80565c4fdfbSgilles tablename, label);
80665c4fdfbSgilles return (LKA_TEMPFAIL);
80765c4fdfbSgilles }
80865c4fdfbSgilles return (LKA_OK);
80965c4fdfbSgilles }
81065c4fdfbSgilles }
81165c4fdfbSgilles
81265c4fdfbSgilles static int
lka_userinfo(const char * tablename,const char * username,struct userinfo * res)81365c4fdfbSgilles lka_userinfo(const char *tablename, const char *username, struct userinfo *res)
81465c4fdfbSgilles {
81565c4fdfbSgilles struct table *table;
816299c4efeSeric union lookup lk;
81765c4fdfbSgilles
818299c4efeSeric log_debug("debug: lka: userinfo %s:%s", tablename, username);
819ff18143eSeric table = table_find(env, tablename);
82065c4fdfbSgilles if (table == NULL) {
82165c4fdfbSgilles log_warnx("warn: cannot find user table %s", tablename);
82265c4fdfbSgilles return (LKA_TEMPFAIL);
82365c4fdfbSgilles }
82465c4fdfbSgilles
82593cc0b04Seric switch (table_lookup(table, K_USERINFO, username, &lk)) {
82665c4fdfbSgilles case -1:
82765c4fdfbSgilles log_warnx("warn: failure during userinfo lookup %s:%s",
82865c4fdfbSgilles tablename, username);
82965c4fdfbSgilles return (LKA_TEMPFAIL);
83065c4fdfbSgilles case 0:
83165c4fdfbSgilles return (LKA_PERMFAIL);
83265c4fdfbSgilles default:
833299c4efeSeric *res = lk.userinfo;
83465c4fdfbSgilles return (LKA_OK);
83565c4fdfbSgilles }
83665c4fdfbSgilles }
83765c4fdfbSgilles
83865c4fdfbSgilles static int
lka_addrname(const char * tablename,const struct sockaddr * sa,struct addrname * res)83965c4fdfbSgilles lka_addrname(const char *tablename, const struct sockaddr *sa,
84065c4fdfbSgilles struct addrname *res)
84165c4fdfbSgilles {
84265c4fdfbSgilles struct table *table;
843299c4efeSeric union lookup lk;
84465c4fdfbSgilles const char *source;
84565c4fdfbSgilles
84665c4fdfbSgilles source = sa_to_text(sa);
84765c4fdfbSgilles
848299c4efeSeric log_debug("debug: lka: helo %s:%s", tablename, source);
849ff18143eSeric table = table_find(env, tablename);
85065c4fdfbSgilles if (table == NULL) {
85165c4fdfbSgilles log_warnx("warn: cannot find helo table %s", tablename);
85265c4fdfbSgilles return (LKA_TEMPFAIL);
85365c4fdfbSgilles }
85465c4fdfbSgilles
85593cc0b04Seric switch (table_lookup(table, K_ADDRNAME, source, &lk)) {
85665c4fdfbSgilles case -1:
85765c4fdfbSgilles log_warnx("warn: failure during helo lookup %s:%s",
85865c4fdfbSgilles tablename, source);
85965c4fdfbSgilles return (LKA_TEMPFAIL);
86065c4fdfbSgilles case 0:
86165c4fdfbSgilles return (LKA_PERMFAIL);
86265c4fdfbSgilles default:
863299c4efeSeric *res = lk.addrname;
86465c4fdfbSgilles return (LKA_OK);
86565c4fdfbSgilles }
86665c4fdfbSgilles }
86765c4fdfbSgilles
86865c4fdfbSgilles static int
lka_mailaddrmap(const char * tablename,const char * username,const struct mailaddr * maddr)869d5f10ab5Sgilles lka_mailaddrmap(const char *tablename, const char *username, const struct mailaddr *maddr)
870d5f10ab5Sgilles {
871d5f10ab5Sgilles struct table *table;
872d5f10ab5Sgilles struct maddrnode *mn;
873d5f10ab5Sgilles union lookup lk;
874d5f10ab5Sgilles int found;
875d5f10ab5Sgilles
876d5f10ab5Sgilles log_debug("debug: lka: mailaddrmap %s:%s", tablename, username);
877ff18143eSeric table = table_find(env, tablename);
878d5f10ab5Sgilles if (table == NULL) {
879d5f10ab5Sgilles log_warnx("warn: cannot find mailaddrmap table %s", tablename);
880d5f10ab5Sgilles return (LKA_TEMPFAIL);
881d5f10ab5Sgilles }
882d5f10ab5Sgilles
88393cc0b04Seric switch (table_lookup(table, K_MAILADDRMAP, username, &lk)) {
884d5f10ab5Sgilles case -1:
885d5f10ab5Sgilles log_warnx("warn: failure during mailaddrmap lookup %s:%s",
886d5f10ab5Sgilles tablename, username);
887d5f10ab5Sgilles return (LKA_TEMPFAIL);
888d5f10ab5Sgilles case 0:
889d5f10ab5Sgilles return (LKA_PERMFAIL);
890d5f10ab5Sgilles default:
891d5f10ab5Sgilles found = 0;
892d5f10ab5Sgilles TAILQ_FOREACH(mn, &lk.maddrmap->queue, entries) {
893d5f10ab5Sgilles if (!mailaddr_match(maddr, &mn->mailaddr))
894d5f10ab5Sgilles continue;
895d5f10ab5Sgilles found = 1;
896d5f10ab5Sgilles break;
897d5f10ab5Sgilles }
898d5f10ab5Sgilles maddrmap_free(lk.maddrmap);
899d5f10ab5Sgilles if (found)
900d5f10ab5Sgilles return (LKA_OK);
901d5f10ab5Sgilles return (LKA_PERMFAIL);
902d5f10ab5Sgilles }
903d5f10ab5Sgilles return (LKA_OK);
904d5f10ab5Sgilles }
905