diff options
Diffstat (limited to 'smtpd/lka.c')
-rw-r--r-- | smtpd/lka.c | 914 |
1 files changed, 914 insertions, 0 deletions
diff --git a/smtpd/lka.c b/smtpd/lka.c new file mode 100644 index 00000000..6ac21245 --- /dev/null +++ b/smtpd/lka.c @@ -0,0 +1,914 @@ +/* $OpenBSD: lka.c,v 1.243 2019/12/21 10:23:37 gilles Exp $ */ + +/* + * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> + * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> + * Copyright (c) 2012 Eric Faurot <eric@faurot.net> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/tree.h> +#include <sys/socket.h> +#include <sys/wait.h> +#include <sys/uio.h> + +#include <netinet/in.h> + +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <event.h> +#include <netdb.h> +#include <grp.h> /* needed for setgroups */ +#include <imsg.h> +#include <openssl/err.h> +#include <openssl/ssl.h> +#include <pwd.h> +#include <resolv.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "smtpd.h" +#include "log.h" +#include "ssl.h" + +static void lka_imsg(struct mproc *, struct imsg *); +static void lka_shutdown(void); +static void lka_sig_handler(int, short, void *); +static int lka_authenticate(const char *, const char *, const char *); +static int lka_credentials(const char *, const char *, char *, size_t); +static int lka_userinfo(const char *, const char *, struct userinfo *); +static int lka_addrname(const char *, const struct sockaddr *, + struct addrname *); +static int lka_mailaddrmap(const char *, const char *, const struct mailaddr *); + +static void proc_timeout(int fd, short event, void *p); + +struct event ev_proc_ready; + +static void +lka_imsg(struct mproc *p, struct imsg *imsg) +{ + struct table *table; + int ret; + struct sockaddr_storage ss; + struct userinfo userinfo; + struct addrname addrname; + struct envelope evp; + struct mailaddr maddr; + struct msg m; + union lookup lk; + char buf[LINE_MAX]; + const char *tablename, *username, *password, *label, *procname; + uint64_t reqid; + int v; + struct timeval tv; + const char *direction; + const char *rdns; + const char *command; + const char *response; + const char *ciphers; + const char *address; + const char *domain; + const char *helomethod; + const char *heloname; + const char *filter_name; + const char *result; + struct sockaddr_storage ss_src, ss_dest; + int filter_response; + int filter_phase; + const char *filter_param; + uint32_t msgid; + uint32_t subsystems; + uint64_t evpid; + size_t msgsz; + int ok; + int fcrdns; + + if (imsg == NULL) + lka_shutdown(); + + switch (imsg->hdr.type) { + + case IMSG_GETADDRINFO: + case IMSG_GETNAMEINFO: + case IMSG_RES_QUERY: + resolver_dispatch_request(p, imsg); + return; + + case IMSG_CERT_INIT: + case IMSG_CERT_CERTIFICATE: + case IMSG_CERT_VERIFY: + cert_dispatch_request(p, imsg); + return; + + case IMSG_MTA_DNS_HOST: + case IMSG_MTA_DNS_MX: + case IMSG_MTA_DNS_MX_PREFERENCE: + dns_imsg(p, imsg); + return; + + case IMSG_SMTP_CHECK_SENDER: + m_msg(&m, imsg); + m_get_id(&m, &reqid); + m_get_string(&m, &tablename); + m_get_string(&m, &username); + m_get_mailaddr(&m, &maddr); + m_end(&m); + + ret = lka_mailaddrmap(tablename, username, &maddr); + + m_create(p, IMSG_SMTP_CHECK_SENDER, 0, 0, -1); + m_add_id(p, reqid); + m_add_int(p, ret); + m_close(p); + return; + + case IMSG_SMTP_EXPAND_RCPT: + m_msg(&m, imsg); + m_get_id(&m, &reqid); + m_get_envelope(&m, &evp); + m_end(&m); + lka_session(reqid, &evp); + return; + + case IMSG_SMTP_LOOKUP_HELO: + m_msg(&m, imsg); + m_get_id(&m, &reqid); + m_get_string(&m, &tablename); + m_get_sockaddr(&m, (struct sockaddr *)&ss); + m_end(&m); + + ret = lka_addrname(tablename, (struct sockaddr*)&ss, + &addrname); + + m_create(p, IMSG_SMTP_LOOKUP_HELO, 0, 0, -1); + m_add_id(p, reqid); + m_add_int(p, ret); + if (ret == LKA_OK) + m_add_string(p, addrname.name); + m_close(p); + return; + + case IMSG_SMTP_AUTHENTICATE: + m_msg(&m, imsg); + m_get_id(&m, &reqid); + m_get_string(&m, &tablename); + m_get_string(&m, &username); + m_get_string(&m, &password); + m_end(&m); + + if (!tablename[0]) { + m_create(p_parent, IMSG_LKA_AUTHENTICATE, + 0, 0, -1); + m_add_id(p_parent, reqid); + m_add_string(p_parent, username); + m_add_string(p_parent, password); + m_close(p_parent); + return; + } + + ret = lka_authenticate(tablename, username, password); + + m_create(p, IMSG_SMTP_AUTHENTICATE, 0, 0, -1); + m_add_id(p, reqid); + m_add_int(p, ret); + m_close(p); + return; + + case IMSG_MDA_LOOKUP_USERINFO: + m_msg(&m, imsg); + m_get_id(&m, &reqid); + m_get_string(&m, &tablename); + m_get_string(&m, &username); + m_end(&m); + + ret = lka_userinfo(tablename, username, &userinfo); + + m_create(p, IMSG_MDA_LOOKUP_USERINFO, 0, 0, -1); + m_add_id(p, reqid); + m_add_int(p, ret); + if (ret == LKA_OK) + m_add_data(p, &userinfo, sizeof(userinfo)); + m_close(p); + return; + + case IMSG_MTA_LOOKUP_CREDENTIALS: + m_msg(&m, imsg); + m_get_id(&m, &reqid); + m_get_string(&m, &tablename); + m_get_string(&m, &label); + m_end(&m); + + lka_credentials(tablename, label, buf, sizeof(buf)); + + m_create(p, IMSG_MTA_LOOKUP_CREDENTIALS, 0, 0, -1); + m_add_id(p, reqid); + m_add_string(p, buf); + m_close(p); + return; + + case IMSG_MTA_LOOKUP_SOURCE: + m_msg(&m, imsg); + m_get_id(&m, &reqid); + m_get_string(&m, &tablename); + m_end(&m); + + table = table_find(env, tablename); + + m_create(p, IMSG_MTA_LOOKUP_SOURCE, 0, 0, -1); + m_add_id(p, reqid); + + if (table == NULL) { + log_warn("warn: source address table %s missing", + tablename); + m_add_int(p, LKA_TEMPFAIL); + } + else { + ret = table_fetch(table, K_SOURCE, &lk); + if (ret == -1) + m_add_int(p, LKA_TEMPFAIL); + else if (ret == 0) + m_add_int(p, LKA_PERMFAIL); + else { + m_add_int(p, LKA_OK); + m_add_sockaddr(p, + (struct sockaddr *)&lk.source.addr); + } + } + m_close(p); + return; + + case IMSG_MTA_LOOKUP_HELO: + m_msg(&m, imsg); + m_get_id(&m, &reqid); + m_get_string(&m, &tablename); + m_get_sockaddr(&m, (struct sockaddr *)&ss); + m_end(&m); + + ret = lka_addrname(tablename, (struct sockaddr*)&ss, + &addrname); + + m_create(p, IMSG_MTA_LOOKUP_HELO, 0, 0, -1); + m_add_id(p, reqid); + m_add_int(p, ret); + if (ret == LKA_OK) + m_add_string(p, addrname.name); + m_close(p); + return; + + case IMSG_MTA_LOOKUP_SMARTHOST: + m_msg(&m, imsg); + m_get_id(&m, &reqid); + m_get_string(&m, &domain); + m_get_string(&m, &tablename); + m_end(&m); + + table = table_find(env, tablename); + + m_create(p, IMSG_MTA_LOOKUP_SMARTHOST, 0, 0, -1); + m_add_id(p, reqid); + + if (table == NULL) { + log_warn("warn: smarthost table %s missing", tablename); + m_add_int(p, LKA_TEMPFAIL); + } + else { + if (domain == NULL) + ret = table_fetch(table, K_RELAYHOST, &lk); + else + ret = table_lookup(table, K_RELAYHOST, domain, &lk); + + if (ret == -1) + m_add_int(p, LKA_TEMPFAIL); + else if (ret == 0) + m_add_int(p, LKA_PERMFAIL); + else { + m_add_int(p, LKA_OK); + m_add_string(p, lk.relayhost); + } + } + m_close(p); + return; + + case IMSG_CONF_START: + return; + + case IMSG_CONF_END: + if (tracing & TRACE_TABLES) + table_dump_all(env); + + /* fork & exec tables that need it */ + table_open_all(env); + +#if HAVE_PLEDGE + /* revoke proc & exec */ + if (pledge("stdio rpath inet dns getpw recvfd sendfd", + NULL) == -1) + err(1, "pledge"); +#endif + + /* setup proc registering task */ + evtimer_set(&ev_proc_ready, proc_timeout, &ev_proc_ready); + tv.tv_sec = 0; + tv.tv_usec = 10; + evtimer_add(&ev_proc_ready, &tv); + return; + + case IMSG_LKA_OPEN_FORWARD: + lka_session_forward_reply(imsg->data, imsg->fd); + return; + + case IMSG_LKA_AUTHENTICATE: + imsg->hdr.type = IMSG_SMTP_AUTHENTICATE; + m_forward(p_pony, imsg); + return; + + case IMSG_CTL_VERBOSE: + m_msg(&m, imsg); + m_get_int(&m, &v); + m_end(&m); + log_trace_verbose(v); + return; + + case IMSG_CTL_PROFILE: + m_msg(&m, imsg); + m_get_int(&m, &v); + m_end(&m); + profiling = v; + return; + + case IMSG_CTL_UPDATE_TABLE: + ret = 0; + table = table_find(env, imsg->data); + if (table == NULL) { + log_warnx("warn: Lookup table not found: " + "\"%s\"", (char *)imsg->data); + } else + ret = table_update(table); + + m_compose(p_control, + (ret == 1) ? IMSG_CTL_OK : IMSG_CTL_FAIL, + imsg->hdr.peerid, 0, -1, NULL, 0); + return; + + case IMSG_LKA_PROCESSOR_FORK: + m_msg(&m, imsg); + m_get_string(&m, &procname); + m_get_u32(&m, &subsystems); + m_end(&m); + + m_create(p, IMSG_LKA_PROCESSOR_ERRFD, 0, 0, -1); + m_add_string(p, procname); + m_close(p); + + lka_proc_forked(procname, subsystems, imsg->fd); + return; + + case IMSG_LKA_PROCESSOR_ERRFD: + m_msg(&m, imsg); + m_get_string(&m, &procname); + m_end(&m); + + lka_proc_errfd(procname, imsg->fd); + shutdown(imsg->fd, SHUT_WR); + return; + + case IMSG_REPORT_SMTP_LINK_CONNECT: + m_msg(&m, imsg); + m_get_string(&m, &direction); + m_get_timeval(&m, &tv); + m_get_id(&m, &reqid); + m_get_string(&m, &rdns); + m_get_int(&m, &fcrdns); + m_get_sockaddr(&m, (struct sockaddr *)&ss_src); + m_get_sockaddr(&m, (struct sockaddr *)&ss_dest); + m_end(&m); + + lka_report_smtp_link_connect(direction, &tv, reqid, rdns, fcrdns, &ss_src, &ss_dest); + return; + + case IMSG_REPORT_SMTP_LINK_GREETING: + m_msg(&m, imsg); + m_get_string(&m, &direction); + m_get_timeval(&m, &tv); + m_get_id(&m, &reqid); + m_get_string(&m, &domain); + m_end(&m); + + lka_report_smtp_link_greeting(direction, reqid, &tv, domain); + return; + + case IMSG_REPORT_SMTP_LINK_DISCONNECT: + m_msg(&m, imsg); + m_get_string(&m, &direction); + m_get_timeval(&m, &tv); + m_get_id(&m, &reqid); + m_end(&m); + + lka_report_smtp_link_disconnect(direction, &tv, reqid); + return; + + case IMSG_REPORT_SMTP_LINK_IDENTIFY: + m_msg(&m, imsg); + m_get_string(&m, &direction); + m_get_timeval(&m, &tv); + m_get_id(&m, &reqid); + m_get_string(&m, &helomethod); + m_get_string(&m, &heloname); + m_end(&m); + + lka_report_smtp_link_identify(direction, &tv, reqid, helomethod, heloname); + return; + + case IMSG_REPORT_SMTP_LINK_TLS: + m_msg(&m, imsg); + m_get_string(&m, &direction); + m_get_timeval(&m, &tv); + m_get_id(&m, &reqid); + m_get_string(&m, &ciphers); + m_end(&m); + + lka_report_smtp_link_tls(direction, &tv, reqid, ciphers); + return; + + case IMSG_REPORT_SMTP_LINK_AUTH: + m_msg(&m, imsg); + m_get_string(&m, &direction); + m_get_timeval(&m, &tv); + m_get_id(&m, &reqid); + m_get_string(&m, &username); + m_get_string(&m, &result); + m_end(&m); + + lka_report_smtp_link_auth(direction, &tv, reqid, username, result); + return; + + case IMSG_REPORT_SMTP_TX_RESET: + m_msg(&m, imsg); + m_get_string(&m, &direction); + m_get_timeval(&m, &tv); + m_get_id(&m, &reqid); + m_get_u32(&m, &msgid); + m_end(&m); + + lka_report_smtp_tx_reset(direction, &tv, reqid, msgid); + return; + + case IMSG_REPORT_SMTP_TX_BEGIN: + m_msg(&m, imsg); + m_get_string(&m, &direction); + m_get_timeval(&m, &tv); + m_get_id(&m, &reqid); + m_get_u32(&m, &msgid); + m_end(&m); + + lka_report_smtp_tx_begin(direction, &tv, reqid, msgid); + return; + + case IMSG_REPORT_SMTP_TX_MAIL: + m_msg(&m, imsg); + m_get_string(&m, &direction); + m_get_timeval(&m, &tv); + m_get_id(&m, &reqid); + m_get_u32(&m, &msgid); + m_get_string(&m, &address); + m_get_int(&m, &ok); + m_end(&m); + + lka_report_smtp_tx_mail(direction, &tv, reqid, msgid, address, ok); + return; + + case IMSG_REPORT_SMTP_TX_RCPT: + m_msg(&m, imsg); + m_get_string(&m, &direction); + m_get_timeval(&m, &tv); + m_get_id(&m, &reqid); + m_get_u32(&m, &msgid); + m_get_string(&m, &address); + m_get_int(&m, &ok); + m_end(&m); + + lka_report_smtp_tx_rcpt(direction, &tv, reqid, msgid, address, ok); + return; + + case IMSG_REPORT_SMTP_TX_ENVELOPE: + m_msg(&m, imsg); + m_get_string(&m, &direction); + m_get_timeval(&m, &tv); + m_get_id(&m, &reqid); + m_get_u32(&m, &msgid); + m_get_id(&m, &evpid); + m_end(&m); + + lka_report_smtp_tx_envelope(direction, &tv, reqid, msgid, evpid); + return; + + case IMSG_REPORT_SMTP_TX_DATA: + m_msg(&m, imsg); + m_get_string(&m, &direction); + m_get_timeval(&m, &tv); + m_get_id(&m, &reqid); + m_get_u32(&m, &msgid); + m_get_int(&m, &ok); + m_end(&m); + + lka_report_smtp_tx_data(direction, &tv, reqid, msgid, ok); + return; + + case IMSG_REPORT_SMTP_TX_COMMIT: + m_msg(&m, imsg); + m_get_string(&m, &direction); + m_get_timeval(&m, &tv); + m_get_id(&m, &reqid); + m_get_u32(&m, &msgid); + m_get_size(&m, &msgsz); + m_end(&m); + + lka_report_smtp_tx_commit(direction, &tv, reqid, msgid, msgsz); + return; + + case IMSG_REPORT_SMTP_TX_ROLLBACK: + m_msg(&m, imsg); + m_get_string(&m, &direction); + m_get_timeval(&m, &tv); + m_get_id(&m, &reqid); + m_get_u32(&m, &msgid); + m_end(&m); + + lka_report_smtp_tx_rollback(direction, &tv, reqid, msgid); + return; + + case IMSG_REPORT_SMTP_PROTOCOL_CLIENT: + m_msg(&m, imsg); + m_get_string(&m, &direction); + m_get_timeval(&m, &tv); + m_get_id(&m, &reqid); + m_get_string(&m, &command); + m_end(&m); + + lka_report_smtp_protocol_client(direction, &tv, reqid, command); + return; + + case IMSG_REPORT_SMTP_PROTOCOL_SERVER: + m_msg(&m, imsg); + m_get_string(&m, &direction); + m_get_timeval(&m, &tv); + m_get_id(&m, &reqid); + m_get_string(&m, &response); + m_end(&m); + + lka_report_smtp_protocol_server(direction, &tv, reqid, response); + return; + + case IMSG_REPORT_SMTP_FILTER_RESPONSE: + m_msg(&m, imsg); + m_get_string(&m, &direction); + m_get_timeval(&m, &tv); + m_get_id(&m, &reqid); + m_get_int(&m, &filter_phase); + m_get_int(&m, &filter_response); + m_get_string(&m, &filter_param); + m_end(&m); + + lka_report_smtp_filter_response(direction, &tv, reqid, + filter_phase, filter_response, filter_param); + return; + + case IMSG_REPORT_SMTP_TIMEOUT: + m_msg(&m, imsg); + m_get_string(&m, &direction); + m_get_timeval(&m, &tv); + m_get_id(&m, &reqid); + m_end(&m); + + lka_report_smtp_timeout(direction, &tv, reqid); + return; + + case IMSG_FILTER_SMTP_PROTOCOL: + m_msg(&m, imsg); + m_get_id(&m, &reqid); + m_get_int(&m, &filter_phase); + m_get_string(&m, &filter_param); + m_end(&m); + + lka_filter_protocol(reqid, filter_phase, filter_param); + return; + + case IMSG_FILTER_SMTP_BEGIN: + m_msg(&m, imsg); + m_get_id(&m, &reqid); + m_get_string(&m, &filter_name); + m_end(&m); + + lka_filter_begin(reqid, filter_name); + return; + + case IMSG_FILTER_SMTP_END: + m_msg(&m, imsg); + m_get_id(&m, &reqid); + m_end(&m); + + lka_filter_end(reqid); + return; + + case IMSG_FILTER_SMTP_DATA_BEGIN: + m_msg(&m, imsg); + m_get_id(&m, &reqid); + m_end(&m); + + lka_filter_data_begin(reqid); + return; + + case IMSG_FILTER_SMTP_DATA_END: + m_msg(&m, imsg); + m_get_id(&m, &reqid); + m_end(&m); + + lka_filter_data_end(reqid); + return; + + } + + errx(1, "lka_imsg: unexpected %s imsg", imsg_to_str(imsg->hdr.type)); +} + +static void +lka_sig_handler(int sig, short event, void *p) +{ + int status; + pid_t pid; + + switch (sig) { + case SIGCHLD: + do { + pid = waitpid(-1, &status, WNOHANG); + } while (pid > 0 || (pid == -1 && errno == EINTR)); + break; + default: + fatalx("lka_sig_handler: unexpected signal"); + } +} + +void +lka_shutdown(void) +{ + log_debug("debug: lookup agent exiting"); + _exit(0); +} + +int +lka(void) +{ + struct passwd *pw; + struct event ev_sigchld; + + purge_config(PURGE_LISTENERS); + + if ((pw = getpwnam(SMTPD_USER)) == NULL) + fatalx("unknown user " SMTPD_USER); + + config_process(PROC_LKA); + + if (initgroups(pw->pw_name, pw->pw_gid) || + setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || + setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) + fatal("lka: cannot drop privileges"); + + imsg_callback = lka_imsg; + event_init(); + + signal_set(&ev_sigchld, SIGCHLD, lka_sig_handler, NULL); + signal_add(&ev_sigchld, NULL); + signal(SIGINT, SIG_IGN); + signal(SIGTERM, SIG_IGN); + signal(SIGPIPE, SIG_IGN); + signal(SIGHUP, SIG_IGN); + + config_peer(PROC_PARENT); + config_peer(PROC_QUEUE); + config_peer(PROC_CONTROL); + config_peer(PROC_PONY); + + /* Ignore them until we get our config */ + mproc_disable(p_pony); + + lka_report_init(); + lka_filter_init(); + +#if HAVE_PLEDGE + /* proc & exec will be revoked before serving requests */ + if (pledge("stdio rpath inet dns getpw recvfd sendfd proc exec", NULL) == -1) + err(1, "pledge"); +#endif + + event_dispatch(); + fatalx("exited event loop"); + + return (0); +} + +static void +proc_timeout(int fd, short event, void *p) +{ + struct event *ev = p; + struct timeval tv; + + if (!lka_proc_ready()) + goto reset; + + lka_filter_ready(); + mproc_enable(p_pony); + return; + +reset: + tv.tv_sec = 0; + tv.tv_usec = 10; + evtimer_add(ev, &tv); +} + + +static int +lka_authenticate(const char *tablename, const char *user, const char *password) +{ + struct table *table; + union lookup lk; + + log_debug("debug: lka: authenticating for %s:%s", tablename, user); + table = table_find(env, tablename); + if (table == NULL) { + log_warnx("warn: could not find table %s needed for authentication", + tablename); + return (LKA_TEMPFAIL); + } + + switch (table_lookup(table, K_CREDENTIALS, user, &lk)) { + case -1: + log_warnx("warn: user credentials lookup fail for %s:%s", + tablename, user); + return (LKA_TEMPFAIL); + case 0: + return (LKA_PERMFAIL); + default: + if (crypt_checkpass(password, lk.creds.password) == 0) + return (LKA_OK); + return (LKA_PERMFAIL); + } +} + +static int +lka_credentials(const char *tablename, const char *label, char *dst, size_t sz) +{ + struct table *table; + union lookup lk; + char *buf; + int buflen, r; + + table = table_find(env, tablename); + if (table == NULL) { + log_warnx("warn: credentials table %s missing", tablename); + return (LKA_TEMPFAIL); + } + + dst[0] = '\0'; + + switch (table_lookup(table, K_CREDENTIALS, label, &lk)) { + case -1: + log_warnx("warn: credentials lookup fail for %s:%s", + tablename, label); + return (LKA_TEMPFAIL); + case 0: + log_warnx("warn: credentials not found for %s:%s", + tablename, label); + return (LKA_PERMFAIL); + default: + if ((buflen = asprintf(&buf, "%c%s%c%s", '\0', + lk.creds.username, '\0', lk.creds.password)) == -1) { + log_warn("warn"); + return (LKA_TEMPFAIL); + } + + r = base64_encode((unsigned char *)buf, buflen, dst, sz); + free(buf); + + if (r == -1) { + log_warnx("warn: credentials parse error for %s:%s", + tablename, label); + return (LKA_TEMPFAIL); + } + return (LKA_OK); + } +} + +static int +lka_userinfo(const char *tablename, const char *username, struct userinfo *res) +{ + struct table *table; + union lookup lk; + + log_debug("debug: lka: userinfo %s:%s", tablename, username); + table = table_find(env, tablename); + if (table == NULL) { + log_warnx("warn: cannot find user table %s", tablename); + return (LKA_TEMPFAIL); + } + + switch (table_lookup(table, K_USERINFO, username, &lk)) { + case -1: + log_warnx("warn: failure during userinfo lookup %s:%s", + tablename, username); + return (LKA_TEMPFAIL); + case 0: + return (LKA_PERMFAIL); + default: + *res = lk.userinfo; + return (LKA_OK); + } +} + +static int +lka_addrname(const char *tablename, const struct sockaddr *sa, + struct addrname *res) +{ + struct table *table; + union lookup lk; + const char *source; + + source = sa_to_text(sa); + + log_debug("debug: lka: helo %s:%s", tablename, source); + table = table_find(env, tablename); + if (table == NULL) { + log_warnx("warn: cannot find helo table %s", tablename); + return (LKA_TEMPFAIL); + } + + switch (table_lookup(table, K_ADDRNAME, source, &lk)) { + case -1: + log_warnx("warn: failure during helo lookup %s:%s", + tablename, source); + return (LKA_TEMPFAIL); + case 0: + return (LKA_PERMFAIL); + default: + *res = lk.addrname; + return (LKA_OK); + } +} + +static int +lka_mailaddrmap(const char *tablename, const char *username, const struct mailaddr *maddr) +{ + struct table *table; + struct maddrnode *mn; + union lookup lk; + int found; + + log_debug("debug: lka: mailaddrmap %s:%s", tablename, username); + table = table_find(env, tablename); + if (table == NULL) { + log_warnx("warn: cannot find mailaddrmap table %s", tablename); + return (LKA_TEMPFAIL); + } + + switch (table_lookup(table, K_MAILADDRMAP, username, &lk)) { + case -1: + log_warnx("warn: failure during mailaddrmap lookup %s:%s", + tablename, username); + return (LKA_TEMPFAIL); + case 0: + return (LKA_PERMFAIL); + default: + found = 0; + TAILQ_FOREACH(mn, &lk.maddrmap->queue, entries) { + if (!mailaddr_match(maddr, &mn->mailaddr)) + continue; + found = 1; + break; + } + maddrmap_free(lk.maddrmap); + if (found) + return (LKA_OK); + return (LKA_PERMFAIL); + } + return (LKA_OK); +} |