summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Faurot <eric@cvs.openbsd.org>2013-07-20 09:06:47 +0000
committerEric Faurot <eric@cvs.openbsd.org>2013-07-20 09:06:47 +0000
commit423fb084212ae7bd9fb0bf673eaa82d7259e724f (patch)
treeeb70b490f97fcad2ce2d58da5fc61100c5094d98
parentd7a4fe68373b71c4e4bec9c27af2d346d28920df (diff)
Update ldap and sqlite table backends and provide them as external backends.
-rw-r--r--usr.sbin/smtpd/Makefile4
-rw-r--r--usr.sbin/smtpd/table-ldap/Makefile28
-rw-r--r--usr.sbin/smtpd/table-sqlite/Makefile27
-rw-r--r--usr.sbin/smtpd/table.c6
-rw-r--r--usr.sbin/smtpd/table_api.c6
-rw-r--r--usr.sbin/smtpd/table_ldap.c912
-rw-r--r--usr.sbin/smtpd/table_sqlite.c709
7 files changed, 888 insertions, 804 deletions
diff --git a/usr.sbin/smtpd/Makefile b/usr.sbin/smtpd/Makefile
index 06920b9248e..d26558ad77d 100644
--- a/usr.sbin/smtpd/Makefile
+++ b/usr.sbin/smtpd/Makefile
@@ -1,7 +1,9 @@
-# $OpenBSD: Makefile,v 1.10 2013/05/24 17:03:14 eric Exp $
+# $OpenBSD: Makefile,v 1.11 2013/07/20 09:06:46 eric Exp $
.include <bsd.own.mk>
SUBDIR = makemap smtpd smtpctl
+SUBDIR+= table-ldap
+SUBDIR+= table-sqlite
.include <bsd.subdir.mk>
diff --git a/usr.sbin/smtpd/table-ldap/Makefile b/usr.sbin/smtpd/table-ldap/Makefile
new file mode 100644
index 00000000000..1a766b71877
--- /dev/null
+++ b/usr.sbin/smtpd/table-ldap/Makefile
@@ -0,0 +1,28 @@
+# $OpenBSD: Makefile,v 1.1 2013/07/20 09:06:46 eric Exp $
+
+.PATH: ${.CURDIR}/..
+
+PROG= table-ldap
+
+SRCS= table_ldap.c
+SRCS+= table_api.c
+SRCS+= aldap.c
+SRCS+= ber.c
+SRCS+= log.c
+
+NOMAN= noman
+
+BINDIR= /usr/libexec/smtpd
+
+DPADD= ${LIBUTIL}
+LDADD= -lutil
+
+CFLAGS+= -g3 -ggdb -I${.CURDIR}/..
+CFLAGS+= -Wall -Wstrict-prototypes -Wmissing-prototypes
+CFLAGS+= -Wmissing-declarations
+CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual
+CFLAGS+= -Wsign-compare -Wbounded
+CFLAGS+= -DNO_IO
+#CFLAGS+= -Werror # during development phase (breaks some archs)
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/smtpd/table-sqlite/Makefile b/usr.sbin/smtpd/table-sqlite/Makefile
new file mode 100644
index 00000000000..b69b120a0a0
--- /dev/null
+++ b/usr.sbin/smtpd/table-sqlite/Makefile
@@ -0,0 +1,27 @@
+# $OpenBSD: Makefile,v 1.1 2013/07/20 09:06:46 eric Exp $
+
+.PATH: ${.CURDIR}/..
+
+PROG= table-sqlite
+
+SRCS= table_sqlite.c
+SRCS+= table_api.c
+SRCS+= dict.c
+SRCS+= log.c
+
+NOMAN= noman
+
+BINDIR= /usr/libexec/smtpd
+
+DPADD= ${LIBUTIL} ${LIBSQLITE3}
+LDADD= -lutil -lsqlite3
+
+CFLAGS+= -g3 -ggdb -I${.CURDIR}/..
+CFLAGS+= -Wall -Wstrict-prototypes -Wmissing-prototypes
+CFLAGS+= -Wmissing-declarations
+CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual
+CFLAGS+= -Wsign-compare -Wbounded
+CFLAGS+= -DNO_IO
+#CFLAGS+= -Werror # during development phase (breaks some archs)
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/smtpd/table.c b/usr.sbin/smtpd/table.c
index 8cc30983256..45e4210edb0 100644
--- a/usr.sbin/smtpd/table.c
+++ b/usr.sbin/smtpd/table.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: table.c,v 1.6 2013/07/19 19:53:33 eric Exp $ */
+/* $OpenBSD: table.c,v 1.7 2013/07/20 09:06:46 eric Exp $ */
/*
* Copyright (c) 2013 Eric Faurot <eric@openbsd.org>
@@ -205,10 +205,10 @@ table_create(const char *backend, const char *name, const char *tag,
errx(1, "table_create: table \"%s\" already defined", name);
if ((tb = table_backend_lookup(backend)) == NULL) {
- if (snprintf(path, sizeof(path), PATH_TABLES "/backend-table-%s",
+ if (snprintf(path, sizeof(path), PATH_TABLES "/table-%s",
backend) >= (int)sizeof(path)) {
errx(1, "table_create: path too long \""
- PATH_TABLES "/backend-table-%s\"", backend);
+ PATH_TABLES "/table-%s\"", backend);
}
if (stat(path, &sb) == 0) {
tb = table_backend_lookup("proc");
diff --git a/usr.sbin/smtpd/table_api.c b/usr.sbin/smtpd/table_api.c
index 4008d30a884..93ba00ecc41 100644
--- a/usr.sbin/smtpd/table_api.c
+++ b/usr.sbin/smtpd/table_api.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: table_api.c,v 1.1 2013/07/19 19:53:33 eric Exp $ */
+/* $OpenBSD: table_api.c,v 1.2 2013/07/20 09:06:46 eric Exp $ */
/*
* Copyright (c) 2013 Eric Faurot <eric@openbsd.org>
@@ -44,8 +44,10 @@ static struct imsg imsg;
static size_t rlen;
static char *rdata;
static struct ibuf *buf;
+#if 0
static char *rootpath;
static char *user = SMTPD_USER;
+#endif
static void
table_msg_get(void *dst, size_t len)
@@ -229,7 +231,9 @@ table_api_on_fetch(int(*cb)(int, char *, size_t))
int
table_api_dispatch(void)
{
+#if 0
struct passwd *pw;
+#endif
ssize_t n;
#if 0
diff --git a/usr.sbin/smtpd/table_ldap.c b/usr.sbin/smtpd/table_ldap.c
index f3aff8b43a7..51d170144cb 100644
--- a/usr.sbin/smtpd/table_ldap.c
+++ b/usr.sbin/smtpd/table_ldap.c
@@ -1,7 +1,7 @@
-/* $OpenBSD: table_ldap.c,v 1.4 2013/05/24 17:03:14 eric Exp $ */
+/* $OpenBSD: table_ldap.c,v 1.5 2013/07/20 09:06:46 eric Exp $ */
/*
- * Copyright (c) 2010-2012 Gilles Chehade <gilles@poolp.org>
+ * Copyright (c) 2013 Eric Faurot <eric@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -17,237 +17,422 @@
*/
#include <sys/types.h>
-#include <sys/queue.h>
-#include <sys/tree.h>
-#include <sys/socket.h>
-
-#include <netinet/in.h>
-#include <arpa/inet.h>
#include <ctype.h>
-#include <err.h>
-#include <errno.h>
-#include <event.h>
-#include <fcntl.h>
-#include <imsg.h>
-#include <stdio.h>
+#include <getopt.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include "smtpd.h"
-#include "aldap.h"
+#include "smtpd-defines.h"
+#include "smtpd-api.h"
#include "log.h"
+#include "aldap.h"
-#define MAX_LDAP_IDENTIFIER 32
-#define MAX_LDAP_URL 256
-#define MAX_LDAP_USERNAME 256
-#define MAX_LDAP_PASSWORD 256
-#define MAX_LDAP_BASELEN 128
-#define MAX_LDAP_FILTERLEN 1024
-#define MAX_LDAP_FIELDLEN 128
-
-static void *table_ldap_open(struct table *);
-static int table_ldap_update(struct table *);
-static int table_ldap_config(struct table *);
-static int table_ldap_lookup(void *, const char *, enum table_service, union lookup *);
-static int table_ldap_fetch(void *, enum table_service, union lookup *);
-static void table_ldap_close(void *);
-static struct aldap *ldap_client_connect(const char *);
-
-struct table_backend table_backend_ldap = {
- K_ALIAS|K_CREDENTIALS|K_DOMAIN|K_USERINFO, /* K_NETADDR|K_SOURCE,*/
- table_ldap_config,
- table_ldap_open,
- table_ldap_update,
- table_ldap_close,
- table_ldap_lookup,
- table_ldap_fetch
+#define MAX_LDAP_IDENTIFIER 32
+#define MAX_LDAP_URL 256
+#define MAX_LDAP_USERNAME 256
+#define MAX_LDAP_PASSWORD 256
+#define MAX_LDAP_BASELEN 128
+#define MAX_LDAP_FILTERLEN 1024
+#define MAX_LDAP_FIELDLEN 128
+
+
+enum {
+ LDAP_ALIAS = 0,
+ LDAP_DOMAIN,
+ LDAP_CREDENTIALS,
+ LDAP_NETADDR,
+ LDAP_USERINFO,
+ LDAP_SOURCE,
+ LDAP_MAILADDR,
+ LDAP_ADDRNAME,
+
+ LDAP_MAX
};
-struct table_ldap_handle {
- struct aldap *aldap;
- struct table *table;
+#define MAX_ATTRS 6
+
+struct query {
+ char *filter;
+ char *attrs[MAX_ATTRS];
+ int attrn;
};
-static int parse_attributes(char **, const char *, size_t);
-static int table_ldap_internal_query(struct aldap *, const char *,
- const char *, char **, char ***, size_t);
+static int table_ldap_update(void);
+static int table_ldap_check(int, const char *);
+static int table_ldap_lookup(int, const char *, char *, size_t);
+static int table_ldap_fetch(int, char *, size_t);
-static int table_ldap_alias(struct table_ldap_handle *, const char *, union lookup *);
-static int table_ldap_credentials(struct table_ldap_handle *, const char *, union lookup *);
-static int table_ldap_domain(struct table_ldap_handle *, const char *, union lookup *);
-static int table_ldap_userinfo(struct table_ldap_handle *, const char *, union lookup *);
+static int ldap_config(void);
+static int ldap_open(void);
+static int ldap_query(const char *, char **, char ***, size_t);
+static int ldap_parse_attributes(char **, const char *, const char *, size_t);
+static int ldap_run_query(int type, const char *, char *, size_t);
+static char *config;
-static int
-table_ldap_config(struct table *table)
+static char *url;
+static char *username;
+static char *password;
+static char *basedn;
+
+static struct aldap *aldap;
+static struct query queries[LDAP_MAX];
+
+int
+main(int argc, char **argv)
{
- struct table *cfg = NULL;
+ int ch;
- /* no config ? broken */
- if (table->t_config[0] == '\0')
- return 0;
+ log_init(1);
+ log_verbose(~0);
- cfg = table_create("static", table->t_name, "conf", table->t_config);
- if (!table_config(cfg))
- goto err;
+ while ((ch = getopt(argc, argv, "")) != -1) {
+ switch (ch) {
+ default:
+ log_warnx("warn: table-ldap: bad option");
+ return (1);
+ /* NOTREACHED */
+ }
+ }
+ argc -= optind;
+ argv += optind;
- /* sanity checks */
- if (table_get(cfg, "url") == NULL) {
- log_warnx("table_ldap: missing 'url' configuration");
- goto err;
+ if (argc != 1) {
+ log_warnx("warn: table-ldap: bogus argument(s)");
+ return (1);
}
- if (table_get(cfg, "basedn") == NULL) {
- log_warnx("table_ldap: missing 'basedn' configuration");
- goto err;
+ config = argv[0];
+
+ if (!ldap_config()) {
+ log_warnx("warn: table-ldap: could not parse config");
+ return (1);
}
- return 1;
+ log_debug("debug: table-ldap: done reading config");
-err:
- table_destroy(cfg);
- return 0;
+ if (!ldap_open()) {
+ log_warnx("warn: table-ldap: failed to connect");
+ return (1);
+ }
+
+ log_debug("debug: table-ldap: connected");
+ table_api_on_update(table_ldap_update);
+ table_api_on_check(table_ldap_check);
+ table_api_on_lookup(table_ldap_lookup);
+ table_api_on_fetch(table_ldap_fetch);
+ table_api_dispatch();
+
+ return (0);
}
static int
-table_ldap_update(struct table *table)
+table_ldap_update(void)
{
- return 1;
+ return (1);
}
-static void *
-table_ldap_open(struct table *table)
+static int
+table_ldap_check(int service, const char *key)
{
- struct table *cfg = NULL;
- struct table_ldap_handle *tlh = NULL;
- struct aldap_message *message = NULL;
- char *url = NULL;
- char *username = NULL;
- char *password = NULL;
-
- cfg = table_find(table->t_name, "conf");
- if (table_get(cfg, "url") == NULL ||
- table_get(cfg, "username") == NULL ||
- table_get(cfg, "password") == NULL)
- goto err;
-
- url = xstrdup(table_get(cfg, "url"), "table_ldap_open");
- username = xstrdup(table_get(cfg, "username"), "table_ldap_open");
- password = xstrdup(table_get(cfg, "password"), "table_ldap_open");
-
- tlh = xcalloc(1, sizeof(*tlh), "table_ldap_open");
- tlh->table = table;
- tlh->aldap = ldap_client_connect(url);
- if (tlh->aldap == NULL) {
- log_warnx("table_ldap_open: ldap_client_connect error");
- goto err;
+ switch(service) {
+ case K_ALIAS:
+ case K_DOMAIN:
+ case K_CREDENTIALS:
+ case K_USERINFO:
+ return ldap_run_query(service, key, NULL, 0);
+ default:
+ return (-1);
}
+}
- if (aldap_bind(tlh->aldap, username, password) == -1) {
- log_warnx("table_ldap_open: aldap_bind error");
- goto err;
+static int
+table_ldap_lookup(int service, const char *key, char *dst, size_t sz)
+{
+ switch(service) {
+ case K_ALIAS:
+ case K_DOMAIN:
+ case K_CREDENTIALS:
+ case K_USERINFO:
+ return ldap_run_query(service, key, dst, sz);
+ default:
+ return (-1);
}
+}
- if ((message = aldap_parse(tlh->aldap)) == NULL) {
- log_warnx("table_ldap_open: aldap_parse");
- goto err;
+static int
+table_ldap_fetch(int service, char *dst, size_t sz)
+{
+ return (-1);
+}
+
+static struct aldap *
+ldap_connect(const char *addr)
+{
+ struct aldap_url lu;
+ struct addrinfo hints, *res0, *res;
+ char *buf;
+ int error, fd = -1;
+
+ if ((buf = strdup(addr)) == NULL)
+ return (NULL);
+
+ /* XXX buf leak */
+
+ if (aldap_parse_url(buf, &lu) != 1) {
+ log_warnx("warn: table-ldap: ldap_parse_url fail");
+ return (NULL);
}
- switch (aldap_get_resultcode(message)) {
- case LDAP_SUCCESS:
- log_warnx("table_ldap_open: ldap server accepted credentials");
- break;
- case LDAP_INVALID_CREDENTIALS:
- log_warnx("table_ldap_open: ldap server refused credentials");
- goto err;
- default:
- log_warnx("table_ldap_open: failed to bind, result #%d", aldap_get_resultcode(message));
- goto err;
+ bzero(&hints, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM; /* DUMMY */
+ error = getaddrinfo(lu.host, NULL, &hints, &res0);
+ if (error == EAI_AGAIN || error == EAI_NODATA || error == EAI_NONAME)
+ return (NULL);
+ if (error) {
+ log_warnx("warn: table-ldap: could not parse \"%s\": %s",
+ lu.host, gai_strerror(error));
+ return (NULL);
}
- return tlh;
+ for (res = res0; res; res = res->ai_next) {
+ if (res->ai_family != AF_INET && res->ai_family != AF_INET6)
+ continue;
+
+ fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ if (fd == -1)
+ continue;
-err:
- if (tlh) {
- if (tlh->aldap != NULL)
- aldap_close(tlh->aldap);
- free(tlh);
+ if (res->ai_family == AF_INET) {
+ struct sockaddr_in sin4 = *(struct sockaddr_in *)res->ai_addr;
+ sin4.sin_port = htons(lu.port);
+ if (connect(fd, (struct sockaddr *)&sin4, res->ai_addrlen) == 0)
+ return aldap_init(fd);
+ }
+ else if (res->ai_family == AF_INET6) {
+ struct sockaddr_in6 sin6 = *(struct sockaddr_in6 *)res->ai_addr;
+ sin6.sin6_port = htons(lu.port);
+ if (connect(fd, (struct sockaddr *)&sin6, res->ai_addrlen) == 0)
+ return aldap_init(fd);
+ }
+
+ close(fd);
+ fd = -1;
}
- if (message != NULL)
- aldap_freemsg(message);
- return NULL;
+
+ return (NULL);
}
-static void
-table_ldap_close(void *hdl)
+static int
+read_value(char **store, const char *key, const char *value)
{
- struct table_ldap_handle *tlh = hdl;
+ log_debug("debug: table-ldap: reading key \"%s\" -> \"%s\"",
+ key, value);
+
+ if (*store) {
+ log_warnx("warn: table-ldap: duplicate key %s", key);
+ return (0);
+ }
+
+ if ((*store = strdup(value)) == NULL) {
+ log_warn("warn: table-ldap: strdup");
+ return (0);
+ }
- aldap_close(tlh->aldap);
- free(tlh);
+ return (1);
}
static int
-table_ldap_lookup(void *hdl, const char *key, enum table_service service,
- union lookup *lk)
+ldap_parse_attributes(char **attributes, const char *key, const char *line,
+ size_t expect)
{
- struct table_ldap_handle *tlh = hdl;
-
- switch (service) {
- case K_ALIAS:
- return table_ldap_alias(tlh, key, lk);
-
- case K_CREDENTIALS:
- return table_ldap_credentials(tlh, key, lk);
+ char buffer[1024];
+ char *p;
+ size_t m, n;
- case K_DOMAIN:
- return table_ldap_domain(tlh, key, lk);
+ log_debug("debug: table-ldap: parsing attribute \"%s\" (%zu) -> \"%s\"",
+ key, expect, line);
- case K_USERINFO:
- return table_ldap_userinfo(tlh, key, lk);
+ if (strlcpy(buffer, line, sizeof buffer) >= sizeof buffer)
+ return (0);
- default:
- break;
+ m = 1;
+ for (p = buffer; *p; ++p) {
+ if (*p == ',') {
+ *p = 0;
+ m++;
+ }
}
+ if (expect != m)
+ return (0);
- return 0;
+ p = buffer;
+ for (n = 0; n < expect; ++n)
+ attributes[n] = NULL;
+ for (n = 0; n < m; ++n) {
+ attributes[n] = strdup(p);
+ if (attributes[n] == NULL) {
+ log_warnx("warn: table-ldap: strdup");
+ return (0); /* XXX cleanup */
+ }
+ p += strlen(p) + 1;
+ }
+ return (1);
}
static int
-table_ldap_fetch(void *hdl, enum table_service service, union lookup *lk)
+ldap_config(void)
{
- /* fetch not support for LDAP at this point */
- return -1;
+ size_t flen;
+ FILE *fp;
+ char *key, *value, *buf, *lbuf;
+
+ fp = fopen(config, "r");
+ if (fp == NULL)
+ return (0);
+
+ lbuf = NULL;
+ while ((buf = fgetln(fp, &flen))) {
+ if (buf[flen - 1] == '\n')
+ buf[flen - 1] = '\0';
+ else {
+ lbuf = malloc(flen + 1);
+ if (lbuf == NULL) {
+ log_warn("warn: table-ldap: malloc");
+ return (0);
+ }
+ memcpy(lbuf, buf, flen);
+ lbuf[flen] = '\0';
+ buf = lbuf;
+ }
+
+ key = buf;
+ while (isspace((int)*key))
+ ++key;
+ if (*key == '\0' || *key == '#')
+ continue;
+ value = key;
+ strsep(&value, " \t:");
+ if (value) {
+ while (*value) {
+ if (!isspace(*value) &&
+ !(*value == ':' && isspace(*(value + 1))))
+ break;
+ ++value;
+ }
+ if (*value == '\0')
+ value = NULL;
+ }
+
+ if (value == NULL) {
+ log_warnx("warn: table-ldap: missing value for key %s", key);
+ continue;
+ }
+
+ if (!strcmp(key, "url"))
+ read_value(&url, key, value);
+ else if (!strcmp(key, "username"))
+ read_value(&username, key, value);
+ else if (!strcmp(key, "password"))
+ read_value(&password, key, value);
+ else if (!strcmp(key, "basedn"))
+ read_value(&basedn, key, value);
+
+ else if (!strcmp(key, "alias_filter"))
+ read_value(&queries[LDAP_ALIAS].filter, key, value);
+ else if (!strcmp(key, "alias_attributes"))
+ ldap_parse_attributes(queries[LDAP_ALIAS].attrs,
+ key, value, 1);
+
+ else if (!strcmp(key, "credentials_filter"))
+ read_value(&queries[LDAP_CREDENTIALS].filter, key, value);
+ else if (!strcmp(key, "credentials_attributes"))
+ ldap_parse_attributes(queries[LDAP_CREDENTIALS].attrs,
+ key, value, 2);
+
+ else if (!strcmp(key, "domain_filter"))
+ read_value(&queries[LDAP_DOMAIN].filter, key, value);
+ else if (!strcmp(key, "domain_attributes"))
+ ldap_parse_attributes(queries[LDAP_DOMAIN].attrs,
+ key, value, 1);
+
+ else if (!strcmp(key, "userinfo_filter"))
+ read_value(&queries[LDAP_USERINFO].filter, key, value);
+ else if (!strcmp(key, "userinfo_attributes"))
+ ldap_parse_attributes(queries[LDAP_USERINFO].attrs,
+ key, value, 4);
+ else
+ log_warnx("warn: table-ldap: bogus entry \"%s\"", key);
+ }
+
+ free(lbuf);
+ fclose(fp);
+ return (1);
}
static int
-filter_expand(char **expfilter, const char *filter, const char *key)
+ldap_open(void)
{
- if (asprintf(expfilter, filter, key) < 0)
- return 0;
- return 1;
+ struct aldap_message *amsg = NULL;
+
+ aldap = ldap_connect(url);
+ if (aldap == NULL) {
+ log_warnx("warn: table-ldap: ldap_connect error");
+ goto err;
+ }
+
+ if (aldap_bind(aldap, username, password) == -1) {
+ log_warnx("warn: table-ldap: aldap_bind error");
+ goto err;
+ }
+
+ if ((amsg = aldap_parse(aldap)) == NULL) {
+ log_warnx("warn: table-ldap: aldap_parse");
+ goto err;
+ }
+
+ switch (aldap_get_resultcode(amsg)) {
+ case LDAP_SUCCESS:
+ log_debug("debug: table-ldap: ldap server accepted credentials");
+ break;
+ case LDAP_INVALID_CREDENTIALS:
+ log_warnx("warn: table-ldap: ldap server refused credentials");
+ goto err;
+ default:
+ log_warnx("warn: table-ldap: failed to bind, result #%d",
+ aldap_get_resultcode(amsg));
+ goto err;
+ }
+
+ if (amsg)
+ aldap_freemsg(amsg);
+ return (1);
+
+err:
+ if (aldap)
+ aldap_close(aldap);
+ if (amsg)
+ aldap_freemsg(amsg);
+ return (0);
}
static int
-table_ldap_internal_query(struct aldap *aldap, const char *basedn,
- const char *filter, char **attributes, char ***outp, size_t n)
+ldap_query(const char *filter, char **attributes, char ***outp, size_t n)
{
- struct aldap_message *m = NULL;
- struct aldap_page_control *pg = NULL;
- int ret;
- int found;
- size_t i;
- char basedn__[MAX_LDAP_BASELEN];
- char filter__[MAX_LDAP_FILTERLEN];
-
- if (strlcpy(basedn__, basedn, sizeof basedn__)
- >= sizeof basedn__)
+ struct aldap_message *m = NULL;
+ struct aldap_page_control *pg = NULL;
+ int ret, found;
+ size_t i;
+ char basedn__[MAX_LDAP_BASELEN];
+ char filter__[MAX_LDAP_FILTERLEN];
+
+ if (strlcpy(basedn__, basedn, sizeof basedn__) >= sizeof basedn__)
return -1;
- if (strlcpy(filter__, filter, sizeof filter__)
- >= sizeof filter__)
+ if (strlcpy(filter__, filter, sizeof filter__) >= sizeof filter__)
return -1;
found = 0;
do {
@@ -296,360 +481,73 @@ end:
return ret;
}
-
-static int
-table_ldap_credentials(struct table_ldap_handle *tlh, const char *key, union lookup *lk)
-{
- struct aldap *aldap = tlh->aldap;
- struct table *cfg = table_find(tlh->table->t_name, "conf");
- const char *filter = NULL;
- const char *basedn = NULL;
- char *expfilter = NULL;
- char *attributes[4];
- char **ret_attr[4];
- const char *attr;
- char line[1024];
- int ret = -1;
- size_t i;
-
- bzero(&attributes, sizeof attributes);
- bzero(&ret_attr, sizeof ret_attr);
-
- basedn = table_get(cfg, "basedn");
- if ((filter = table_get(cfg, "credentials_filter")) == NULL) {
- log_warnx("table_ldap: lookup: no filter configured for credentials");
- goto end;
- }
-
- if ((attr = table_get(cfg, "credentials_attributes")) == NULL) {
- log_warnx("table_ldap: lookup: no attributes configured for credentials");
- goto end;
- }
-
- if (! filter_expand(&expfilter, filter, key)) {
- log_warnx("table_ldap: lookup: couldn't expand filter");
- goto end;
- }
-
- if (! parse_attributes(attributes, attr, 2)) {
- log_warnx("table_ldap: lookup: failed to parse attributes");
- goto end;
- }
-
- if ((ret = table_ldap_internal_query(aldap, basedn, expfilter, attributes,
- ret_attr, nitems(attributes))) <= 0)
- goto end;
-
- if (lk == NULL)
- goto end;
-
- if (! bsnprintf(line, sizeof line, "%s:%s", ret_attr[0][0], ret_attr[0][1])) {
- ret = -1;
- goto end;
- }
-
- bzero(&lk->creds, sizeof(lk->creds));
- if (! text_to_credentials(&lk->creds, line))
- ret = -1;
-
-end:
- for (i = 0; i < nitems(attributes); ++i) {
- free(attributes[i]);
- if (ret_attr[i])
- aldap_free_attr(ret_attr[i]);
- }
-
- free(expfilter);
- log_debug("debug: table_ldap_credentials: ret=%d", ret);
- return ret;
-}
-
static int
-table_ldap_domain(struct table_ldap_handle *tlh, const char *key, union lookup *lk)
+ldap_run_query(int type, const char *key, char *dst, size_t sz)
{
- struct aldap *aldap = tlh->aldap;
- struct table *cfg = table_find(tlh->table->t_name, "conf");
- const char *filter = NULL;
- const char *basedn = NULL;
- char *expfilter = NULL;
- char *attributes[1];
- char **ret_attr[1];
- const char *attr;
- int ret = -1;
- size_t i;
-
- bzero(&attributes, sizeof attributes);
- bzero(&ret_attr, sizeof ret_attr);
-
- log_debug("domain: %s", key);
- basedn = table_get(cfg, "basedn");
- if ((filter = table_get(cfg, "domain_filter")) == NULL) {
- log_warnx("table_ldap: lookup: no filter configured for domain");
- goto end;
- }
-
- if ((attr = table_get(cfg, "domain_attributes")) == NULL) {
- log_warnx("table_ldap: lookup: no attributes configured for domain");
- goto end;
- }
-
- if (! filter_expand(&expfilter, filter, key)) {
- log_warnx("table_ldap: lookup: couldn't expand filter");
- goto end;
- }
-
- if (! parse_attributes(attributes, attr, 1)) {
- log_warnx("table_ldap: lookup: failed to parse attributes");
- goto end;
- }
-
- if ((ret = table_ldap_internal_query(aldap, basedn, expfilter, attributes,
- ret_attr, nitems(attributes))) <= 0)
- goto end;
-
- if (lk == NULL)
- goto end;
-
- bzero(&lk->domain, sizeof(lk->domain));
- if (strlcpy(lk->domain.name, ret_attr[0][0], sizeof(lk->domain.name))
- >= sizeof(lk->domain.name))
- ret = -1;
-
-end:
- for (i = 0; i < nitems(attributes); ++i) {
- free(attributes[i]);
- if (ret_attr[i])
- aldap_free_attr(ret_attr[i]);
- }
- free(expfilter);
- log_debug("debug: table_ldap_domain: ret=%d", ret);
- return ret;
-}
-
-static int
-table_ldap_userinfo(struct table_ldap_handle *tlh, const char *key, union lookup *lk)
-{
- struct aldap *aldap = tlh->aldap;
- struct table *cfg = table_find(tlh->table->t_name, "conf");
- const char *filter = NULL;
- const char *basedn = NULL;
- char *expfilter = NULL;
- char *attributes[4];
- char **ret_attr[4];
- const char *attr;
- char line[1024];
- int ret = -1;
- size_t i;
-
- bzero(&attributes, sizeof attributes);
- bzero(&ret_attr, sizeof ret_attr);
-
- basedn = table_get(cfg, "basedn");
- if ((filter = table_get(cfg, "userinfo_filter")) == NULL) {
- log_warnx("table_ldap: lookup: no filter configured for userinfo");
- goto end;
- }
-
- if ((attr = table_get(cfg, "userinfo_attributes")) == NULL) {
- log_warnx("table_ldap: lookup: no attributes configured for userinfo");
- goto end;
- }
-
- if (! filter_expand(&expfilter, filter, key)) {
- log_warnx("table_ldap: lookup: couldn't expand filter");
- goto end;
- }
-
- if (! parse_attributes(attributes, attr, 4)) {
- log_warnx("table_ldap: lookup: failed to parse attributes");
- goto end;
- }
-
- if ((ret = table_ldap_internal_query(aldap, basedn, expfilter, attributes,
- ret_attr, nitems(attributes))) <= 0)
- goto end;
-
- if (lk == NULL)
- goto end;
-
- if (! bsnprintf(line, sizeof line, "%s:%s:%s:%s",
- ret_attr[0][0], ret_attr[1][0], ret_attr[2][0], ret_attr[3][0])) {
- ret = -1;
- goto end;
- }
-
- bzero(&lk->userinfo, sizeof(lk->userinfo));
- if (!text_to_userinfo(&(lk->userinfo), line))
- ret = -1;
-
-end:
- for (i = 0; i < nitems(attributes); ++i) {
- free(attributes[i]);
- if (ret_attr[i])
- aldap_free_attr(ret_attr[i]);
- }
- free(expfilter);
- log_debug("debug: table_ldap_userinfo: ret=%d", ret);
- return ret;
-}
-
-static int
-table_ldap_alias(struct table_ldap_handle *tlh, const char *key, union lookup *lk)
-{
- struct aldap *aldap = tlh->aldap;
- struct table *cfg = table_find(tlh->table->t_name, "conf");
- const char *filter = NULL;
- const char *basedn = NULL;
- char *expfilter = NULL;
- char *attributes[1];
- char **ret_attr[1];
- const char *attr;
- int ret = -1;
- size_t i;
-
- bzero(&attributes, sizeof attributes);
- bzero(&ret_attr, sizeof ret_attr);
- if (lk)
- lk->expand = NULL;
-
- basedn = table_get(cfg, "basedn");
- if ((filter = table_get(cfg, "alias_filter")) == NULL) {
- log_warnx("table_ldap: lookup: no filter configured for alias");
- goto end;
- }
-
- if ((attr = table_get(cfg, "alias_attributes")) == NULL) {
- log_warnx("table_ldap: lookup: no attributes configured for alias");
- goto end;
- }
-
- if (! filter_expand(&expfilter, filter, key)) {
- log_warnx("table_ldap: lookup: couldn't expand filter");
- goto end;
+ struct query *q;
+ char **res[4], filter[MAX_LDAP_FILTERLEN];
+ int ret, i;
+
+ switch (type) {
+ case K_ALIAS: q = &queries[LDAP_ALIAS]; break;
+ case K_DOMAIN: q = &queries[LDAP_DOMAIN]; break;
+ case K_CREDENTIALS: q = &queries[LDAP_CREDENTIALS]; break;
+ case K_NETADDR: q = &queries[LDAP_NETADDR]; break;
+ case K_USERINFO: q = &queries[LDAP_USERINFO]; break;
+ case K_SOURCE: q = &queries[LDAP_SOURCE]; break;
+ case K_MAILADDR: q = &queries[LDAP_MAILADDR]; break;
+ case K_ADDRNAME: q = &queries[LDAP_ADDRNAME]; break;
+ default:
+ return (-1);
}
- if (! parse_attributes(attributes, attr, 1)) {
- log_warnx("table_ldap: lookup: failed to parse attributes");
- goto end;
+ if (snprintf(filter, sizeof(filter), q->filter, key)
+ >= (int)sizeof(filter)) {
+ log_warnx("warn: table-ldap: filter too large");
+ return (-1);
}
- if ((ret = table_ldap_internal_query(aldap, basedn, expfilter, attributes,
- ret_attr, nitems(attributes))) <= 0)
+ bzero(res, sizeof(res));
+ ret = ldap_query(filter, q->attrs, res, q->attrn);
+ if (ret <= 0 || dst == NULL)
goto end;
- if (lk == NULL)
- goto end;
-
- lk->expand = xcalloc(1, sizeof(*lk->expand), "table_ldap_alias");
- for (i = 0; ret_attr[0][i]; ++i) {
- if (! expand_line(lk->expand, ret_attr[0][i], 1)) {
- ret = -1;
- goto end;
- }
- }
+ switch (type) {
-end:
- for (i = 0; i < nitems(attributes); ++i) {
- free(attributes[i]);
- if (ret_attr[i])
- aldap_free_attr(ret_attr[i]);
- }
- if (ret != 1 && lk && lk->expand)
- expand_free(lk->expand);
-
- free(expfilter);
- log_debug("debug: table_ldap_alias: ret=%d", ret);
- return ret;
-}
-
-static struct aldap *
-ldap_client_connect(const char *addr)
-{
- struct aldap_url lu;
- struct addrinfo hints, *res0, *res;
- int error;
-
- char *url;
- int fd = -1;
-
- if ((url = strdup(addr)) == NULL)
- err(1, NULL);
-
- if (aldap_parse_url(url, &lu) != 1) {
- warnx("aldap_parse_url fail");
- goto err;
- }
- url = NULL;
-
- bzero(&hints, sizeof(hints));
- hints.ai_family = PF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM; /* DUMMY */
- error = getaddrinfo(lu.host, NULL, &hints, &res0);
- if (error == EAI_AGAIN || error == EAI_NODATA || error == EAI_NONAME)
- goto err;
- if (error) {
- log_warnx("ldap_client_connect: could not parse \"%s\": %s", lu.host,
- gai_strerror(error));
- goto err;
- }
-
- for (res = res0; res; res = res->ai_next) {
- if (res->ai_family != AF_INET && res->ai_family != AF_INET6)
- continue;
-
- fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
- if (fd == -1)
- continue;
-
- if (res->ai_family == AF_INET) {
- struct sockaddr_in sin4 = *(struct sockaddr_in *)res->ai_addr;
- sin4.sin_port = htons(lu.port);
- if (connect(fd, (struct sockaddr *)&sin4, res->ai_addrlen) == 0)
- return aldap_init(fd);
- }
- else if (res->ai_family == AF_INET6) {
- struct sockaddr_in6 sin6 = *(struct sockaddr_in6 *)res->ai_addr;
- sin6.sin6_port = htons(lu.port);
- if (connect(fd, (struct sockaddr *)&sin6, res->ai_addrlen) == 0)
- return aldap_init(fd);
+ case K_ALIAS:
+ for (i = 0; res[0][i]; i++) {
+ if (i && strlcat(dst, ", ", sz) >= sz) {
+ ret = -1;
+ break;
+ }
+ if (strlcat(dst, res[0][i], sz) >= sz) {
+ ret = -1;
+ break;
+ }
}
-
- close(fd);
- fd = -1;
+ break;
+ case K_DOMAIN:
+ if (strlcpy(dst, res[0][0], sz) >= sz)
+ ret = -1;
+ break;
+ case K_CREDENTIALS:
+ if (snprintf(dst, sz, "%s:%s", res[0][0], res[0][1]) >= (int)sz)
+ ret = -1;
+ break;
+ case K_USERINFO:
+ if (snprintf(dst, sz, "%s:%s:%s:%s", res[0][0], res[1][0],
+ res[2][0], res[3][0]) >= (int)sz)
+ ret = -1;
+ break;
}
-err:
- free(url);
- return NULL;
-}
-
-static int
-parse_attributes(char **attributes, const char *line, size_t expect)
-{
- char buffer[1024];
- char *p;
- size_t m, n;
-
- if (strlcpy(buffer, line, sizeof buffer)
- >= sizeof buffer)
- return 0;
+ if (ret == -1)
+ log_warnx("warn: table-ldap: could not format result");
- m = 1;
- for (p = buffer; *p; ++p) {
- if (*p == ',') {
- *p = 0;
- m++;
- }
- }
- if (expect != m)
- return 0;
+end:
+ for (i = 0; i < q->attrn; ++i)
+ if (res[i])
+ aldap_free_attr(res[i]);
- p = buffer;
- for (n = 0; n < expect; ++n)
- attributes[n] = NULL;
- for (n = 0; n < m; ++n) {
- attributes[n] = xstrdup(p, "parse_attributes");
- p += strlen(p) + 1;
- }
- return 1;
+ return (ret);
}
diff --git a/usr.sbin/smtpd/table_sqlite.c b/usr.sbin/smtpd/table_sqlite.c
index bfcf11fa4d4..9b9dff84240 100644
--- a/usr.sbin/smtpd/table_sqlite.c
+++ b/usr.sbin/smtpd/table_sqlite.c
@@ -1,7 +1,7 @@
-/* $OpenBSD: table_sqlite.c,v 1.3 2013/05/24 17:03:14 eric Exp $ */
+/* $OpenBSD: table_sqlite.c,v 1.4 2013/07/20 09:06:46 eric Exp $ */
/*
- * Copyright (c) 2012 Gilles Chehade <gilles@poolp.org>
+ * Copyright (c) 2013 Eric Faurot <eric@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -17,384 +17,509 @@
*/
#include <sys/types.h>
-#include <sys/queue.h>
-#include <sys/tree.h>
-#include <sys/socket.h>
#include <ctype.h>
-#include <err.h>
-#include <event.h>
#include <fcntl.h>
-#include <imsg.h>
#include <sqlite3.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <time.h>
-#include "smtpd.h"
+#include "smtpd-defines.h"
+#include "smtpd-api.h"
#include "log.h"
-/* sqlite(3) backend */
-static int table_sqlite_config(struct table *);
-static int table_sqlite_update(struct table *);
-static void *table_sqlite_open(struct table *);
-static int table_sqlite_lookup(void *, const char *, enum table_service,
- union lookup *);
-static void table_sqlite_close(void *);
-
-struct table_backend table_backend_sqlite = {
- K_ALIAS|K_CREDENTIALS|K_DOMAIN|K_NETADDR|K_USERINFO,
- table_sqlite_config,
- table_sqlite_open,
- table_sqlite_update,
- table_sqlite_close,
- table_sqlite_lookup,
+enum {
+ SQL_ALIAS = 0,
+ SQL_DOMAIN,
+ SQL_CREDENTIALS,
+ SQL_NETADDR,
+ SQL_USERINFO,
+ SQL_SOURCE,
+ SQL_MAILADDR,
+ SQL_ADDRNAME,
+
+ SQL_MAX
};
-struct table_sqlite_handle {
- sqlite3 *ppDb;
- struct table *table;
-};
+static int table_sqlite_update(void);
+static int table_sqlite_lookup(int, const char *, char *, size_t);
+static int table_sqlite_check(int, const char *);
+static int table_sqlite_fetch(int, char *, size_t);
+
+static sqlite3_stmt *table_sqlite_query(const char *, int);
+
+#define DEFAULT_EXPIRE 60
+#define DEFAULT_REFRESH 1000
+
+static char *config;
+static sqlite3 *db;
+static sqlite3_stmt *statements[SQL_MAX];
+static sqlite3_stmt *stmt_fetch_source;
+static struct dict sources;
+static void *source_iter;
+static size_t source_refresh = 1000;
+static size_t source_ncall;
+static int source_expire = 60;
+static time_t source_update;
+
+int
+main(int argc, char **argv)
+{
+ int ch;
-static int table_sqlite_alias(struct table_sqlite_handle *, const char *, union lookup *);
-static int table_sqlite_domain(struct table_sqlite_handle *, const char *, union lookup *);
-static int table_sqlite_userinfo(struct table_sqlite_handle *, const char *, union lookup *);
-static int table_sqlite_credentials(struct table_sqlite_handle *, const char *, union lookup *);
-static int table_sqlite_netaddr(struct table_sqlite_handle *, const char *, union lookup *);
+ log_init(1);
+ log_verbose(~0);
-static int
-table_sqlite_config(struct table *table)
-{
- struct table *cfg;
+ while ((ch = getopt(argc, argv, "")) != -1) {
+ switch (ch) {
+ default:
+ log_warnx("warn: table-sqlite: bad option");
+ return (1);
+ /* NOTREACHED */
+ }
+ }
+ argc -= optind;
+ argv += optind;
- /* no config ? broken */
- if (table->t_config[0] == '\0')
- return 0;
+ if (argc != 1) {
+ log_warnx("warn: table-sqlite: bogus argument(s)");
+ return (1);
+ }
+
+ config = argv[0];
- cfg = table_create("static", table->t_name, "conf", table->t_config);
- if (!table_config(cfg))
- goto err;
+ dict_init(&sources);
- /* sanity checks */
- if (table_get(cfg, "dbpath") == NULL) {
- log_warnx("table_sqlite: missing 'dbpath' configuration");
- return 0;
+ if (table_sqlite_update() == 0) {
+ log_warnx("warn: table-sqlite: error parsing config file");
+ return (1);
}
- return 1;
+ table_api_on_update(table_sqlite_update);
+ table_api_on_check(table_sqlite_check);
+ table_api_on_lookup(table_sqlite_lookup);
+ table_api_on_fetch(table_sqlite_fetch);
+ table_api_dispatch();
-err:
- table_destroy(cfg);
- return 0;
+ return (0);
}
static int
-table_sqlite_update(struct table *table)
+table_sqlite_getconfstr(const char *key, const char *value, char **var)
{
- log_info("info: Table \"%s\" successfully updated", table->t_name);
- return 1;
+ if (*var) {
+ log_warnx("warn: table-sqlite: duplicate %s %s", key, value);
+ free(*var);
+ }
+ *var = strdup(value);
+ if (*var == NULL) {
+ log_warn("warn: table-sqlite: strdup");
+ return (-1);
+ }
+ return (0);
}
-static void *
-table_sqlite_open(struct table *table)
+static sqlite3_stmt *
+table_sqlite_prepare_stmt(sqlite3 *_db, const char *query, int ncols)
{
- struct table_sqlite_handle *tsh;
- struct table *cfg;
- const char *dbpath;
-
- tsh = xcalloc(1, sizeof *tsh, "table_sqlite_open");
- tsh->table = table;
+ sqlite3_stmt *stmt;
- cfg = table_find(table->t_name, "conf");
- dbpath = table_get(cfg, "dbpath");
-
- if (sqlite3_open(dbpath, &tsh->ppDb) != SQLITE_OK) {
- log_warnx("table_sqlite: open: %s", sqlite3_errmsg(tsh->ppDb));
- free(tsh);
- return NULL;
+ if (sqlite3_prepare_v2(_db, query, -1, &stmt, 0) != SQLITE_OK) {
+ log_warnx("warn: table-sqlite: sqlite3_prepare_v2: %s",
+ sqlite3_errmsg(_db));
+ goto end;
+ }
+ if (sqlite3_column_count(stmt) != ncols) {
+ log_warnx("warn: table-sqlite: columns: invalid resultset");
+ goto end;
}
- return tsh;
-}
-
-static void
-table_sqlite_close(void *hdl)
-{
- return;
+ return (stmt);
+ end:
+ sqlite3_finalize(stmt);
+ return (NULL);
}
static int
-table_sqlite_lookup(void *hdl, const char *key, enum table_service service,
- union lookup *lk)
+table_sqlite_update(void)
{
- struct table_sqlite_handle *tsh = hdl;
+ static const struct {
+ const char *name;
+ int cols;
+ } qspec[SQL_MAX] = {
+ { "query_alias", 1 },
+ { "query_domain", 1 },
+ { "query_credentials", 2 },
+ { "query_netaddr", 1 },
+ { "query_userinfo", 4 },
+ { "query_source", 1 },
+ { "query_mailaddr", 1 },
+ { "query_addrname", 1 },
+ };
+ sqlite3 *_db;
+ sqlite3_stmt *_statements[SQL_MAX];
+ sqlite3_stmt *_stmt_fetch_source;
+ char *_query_fetch_source;
+ char *queries[SQL_MAX];
+ size_t flen;
+ size_t _source_refresh;
+ int _source_expire;
+ FILE *fp;
+ char *key, *value, *buf, *lbuf, *dbpath;
+ const char *e;
+ int i, ret;
+ long long ll;
+
+ dbpath = NULL;
+ _db = NULL;
+ bzero(queries, sizeof(queries));
+ bzero(_statements, sizeof(_statements));
+ _query_fetch_source = NULL;
+ _stmt_fetch_source = NULL;
+
+ _source_refresh = DEFAULT_REFRESH;
+ _source_expire = DEFAULT_EXPIRE;
+
+ ret = 0;
+
+ /* Parse configuration */
+
+ fp = fopen(config, "r");
+ if (fp == NULL)
+ return (0);
+
+ lbuf = NULL;
+ while ((buf = fgetln(fp, &flen))) {
+ if (buf[flen - 1] == '\n')
+ buf[flen - 1] = '\0';
+ else {
+ lbuf = malloc(flen + 1);
+ if (lbuf == NULL) {
+ log_warn("warn: table-sqlite: malloc");
+ return (0);
+ }
+ memcpy(lbuf, buf, flen);
+ lbuf[flen] = '\0';
+ buf = lbuf;
+ }
- switch (service) {
- case K_ALIAS:
- return table_sqlite_alias(tsh, key, lk);
- case K_DOMAIN:
- return table_sqlite_domain(tsh, key, lk);
- case K_USERINFO:
- return table_sqlite_userinfo(tsh, key, lk);
- case K_CREDENTIALS:
- return table_sqlite_credentials(tsh, key, lk);
- case K_NETADDR:
- return table_sqlite_netaddr(tsh, key, lk);
- default:
- log_warnx("table_sqlite: lookup: unsupported lookup service");
- return -1;
- }
+ key = buf;
+ while (isspace((int)*key))
+ ++key;
+ if (*key == '\0' || *key == '#')
+ continue;
+ value = key;
+ strsep(&value, " \t:");
+ if (value) {
+ while (*value) {
+ if (!isspace(*value) &&
+ !(*value == ':' && isspace(*(value + 1))))
+ break;
+ ++value;
+ }
+ if (*value == '\0')
+ value = NULL;
+ }
- return 0;
-}
+ if (value == NULL) {
+ log_warnx("warn: table-sqlite: missing value for key %s", key);
+ continue;
+ }
-static int
-table_sqlite_alias(struct table_sqlite_handle *tsh, const char *key, union lookup *lk)
+ if (!strcmp("dbpath", key)) {
+ if (table_sqlite_getconfstr(key, value, &dbpath) == -1)
+ goto end;
+ continue;
+ }
+ if (!strcmp("fetch_source", key)) {
+ if (table_sqlite_getconfstr(key, value, &_query_fetch_source) == -1)
+ goto end;
+ continue;
+ }
+ if (!strcmp("fetch_source_expire", key)) {
+ e = NULL;
+ ll = strtonum(value, 0, INT_MAX, &e);
+ if (e) {
+ log_warnx("warn: table-sqlite: bad value for %s: %s", key, e);
+ goto end;
+ }
+ _source_expire = ll;
+ continue;
+ }
+ if (!strcmp("fetch_source_refresh", key)) {
+ e = NULL;
+ ll = strtonum(value, 0, INT_MAX, &e);
+ if (e) {
+ log_warnx("warn: table-sqlite: bad value for %s: %s", key, e);
+ goto end;
+ }
+ _source_refresh = ll;
+ continue;
+ }
-{
- struct table *cfg = table_find(tsh->table->t_name, "conf");
- const char *query = table_get(cfg, "query_alias");
- sqlite3_stmt *stmt;
- struct expandnode xn;
- int nrows;
-
- if (query == NULL) {
- log_warnx("table_sqlite: lookup: no query configured for aliases");
- return -1;
- }
+ for(i = 0; i < SQL_MAX; i++)
+ if (!strcmp(qspec[i].name, key))
+ break;
+ if (i == SQL_MAX) {
+ log_warnx("warn: table-sqlite: bogus key %s", key);
+ continue;
+ }
- if (sqlite3_prepare_v2(tsh->ppDb, query, -1, &stmt, 0) != SQLITE_OK) {
- log_warnx("table_sqlite: prepare: %s", sqlite3_errmsg(tsh->ppDb));
- return -1;
- }
+ if (queries[i]) {
+ log_warnx("warn: table-sqlite: duplicate key %s", key);
+ continue;
+ }
- if (sqlite3_column_count(stmt) != 1) {
- log_warnx("table_sqlite: columns: invalid resultset");
- sqlite3_finalize(stmt);
- return -1;
+ queries[i] = strdup(value);
+ if (queries[i] == NULL) {
+ log_warnx("warn: table-sqlite: strdup");
+ goto end;
+ }
}
- if (lk)
- lk->expand = xcalloc(1, sizeof(*lk->expand), "table_sqlite_alias");
+ /* Setup db */
- nrows = 0;
+ log_debug("debug: table-sqlite: opening %s", dbpath);
- sqlite3_bind_text(stmt, 1, key, strlen(key), NULL);
- while (sqlite3_step(stmt) == SQLITE_ROW) {
- if (lk == NULL) {
- sqlite3_finalize(stmt);
- return 1;
- }
- if (! text_to_expandnode(&xn, sqlite3_column_text(stmt, 0)))
- goto error;
- expand_insert(lk->expand, &xn);
- nrows++;
+ if (sqlite3_open(dbpath, &_db) != SQLITE_OK) {
+ log_warnx("warn: table-sqlite: open: %s",
+ sqlite3_errmsg(_db));
+ goto end;
}
- sqlite3_finalize(stmt);
- return nrows ? 1 : 0;
+ for (i = 0; i < SQL_MAX; i++) {
+ if (queries[i] == NULL)
+ continue;
+ if ((_statements[i] = table_sqlite_prepare_stmt(_db, queries[i], qspec[i].cols)) == NULL)
+ goto end;
+ }
-error:
- if (lk && lk->expand)
- expand_free(lk->expand);
- return -1;
-}
+ if (_query_fetch_source &&
+ (_stmt_fetch_source = table_sqlite_prepare_stmt(_db, _query_fetch_source, 1)) == NULL)
+ goto end;
-static int
-table_sqlite_domain(struct table_sqlite_handle *tsh, const char *key, union lookup *lk)
-{
- struct table *cfg = table_find(tsh->table->t_name, "conf");
- const char *query = table_get(cfg, "query_domain");
- sqlite3_stmt *stmt;
-
- if (query == NULL) {
- log_warnx("table_sqlite: lookup: no query configured for domain");
- return -1;
- }
+ /* Replace previous setup */
- if (sqlite3_prepare_v2(tsh->ppDb, query, -1, &stmt, 0) != SQLITE_OK) {
- log_warnx("table_sqlite: prepare: %s", sqlite3_errmsg(tsh->ppDb));
- return -1;
+ for (i = 0; i < SQL_MAX; i++) {
+ if (statements[i])
+ sqlite3_finalize(statements[i]);
+ statements[i] = _statements[i];
+ _statements[i] = NULL;
}
-
- if (sqlite3_column_count(stmt) != 1) {
- log_warnx("table_sqlite: columns: invalid resultset");
- sqlite3_finalize(stmt);
- return -1;
+ if (stmt_fetch_source)
+ sqlite3_finalize(stmt_fetch_source);
+ stmt_fetch_source = _stmt_fetch_source;
+ _stmt_fetch_source = NULL;
+
+ if (db)
+ sqlite3_close(_db);
+ db = _db;
+ _db = NULL;
+
+ source_update = 0; /* force update */
+ source_expire = _source_expire;
+ source_refresh = _source_refresh;
+
+ log_debug("debug: table-sqlite: config successfully updated");
+ ret = 1;
+
+ end:
+
+ /* Cleanup */
+ for (i = 0; i < SQL_MAX; i++) {
+ if (_statements[i])
+ sqlite3_finalize(_statements[i]);
+ free(queries[i]);
}
+ if (_db)
+ sqlite3_close(_db);
- sqlite3_bind_text(stmt, 1, key, strlen(key), NULL);
+ free(dbpath);
+ free(_query_fetch_source);
- switch (sqlite3_step(stmt)) {
- case SQLITE_ROW:
- if (lk)
- strlcpy(lk->domain.name, sqlite3_column_text(stmt, 0), sizeof(lk->domain.name));
- sqlite3_finalize(stmt);
- return 1;
+ free(lbuf);
+ fclose(fp);
+ return (ret);
+}
- case SQLITE_DONE:
- sqlite3_finalize(stmt);
- return 0;
+static sqlite3_stmt *
+table_sqlite_query(const char *key, int service)
+{
+ int i;
+ sqlite3_stmt *stmt;
+
+ stmt = NULL;
+ for(i = 0; i < SQL_MAX; i++)
+ if (service == 1 << i) {
+ stmt = statements[i];
+ break;
+ }
- default:
- sqlite3_finalize(stmt);
+ if (stmt == NULL)
+ return (NULL);
+
+ if (sqlite3_bind_text(stmt, 1, key, strlen(key), NULL) != SQLITE_OK) {
+ log_warnx("table-sqlite: sqlite3_bind_text: %s",
+ sqlite3_errmsg(db));
+ return (NULL);
}
- return -1;
+ return (stmt);
}
static int
-table_sqlite_userinfo(struct table_sqlite_handle *tsh, const char *key, union lookup *lk)
+table_sqlite_check(int service, const char *key)
{
- struct table *cfg = table_find(tsh->table->t_name, "conf");
- const char *query = table_get(cfg, "query_userinfo");
- sqlite3_stmt *stmt;
- size_t s;
-
- if (query == NULL) {
- log_warnx("table_sqlite: lookup: no query configured for user");
- return -1;
- }
-
- if (sqlite3_prepare_v2(tsh->ppDb, query, -1, &stmt, 0) != SQLITE_OK) {
- log_warnx("table_sqlite: prepare: %s", sqlite3_errmsg(tsh->ppDb));
- return -1;
- }
+ sqlite3_stmt *stmt;
+ int r;
- if (sqlite3_column_count(stmt) != 4) {
- log_warnx("table_sqlite: columns: invalid resultset");
- sqlite3_finalize(stmt);
- return -1;
- }
+ stmt = table_sqlite_query(key, service);
+ if (stmt == NULL)
+ return (-1);
- sqlite3_bind_text(stmt, 1, key, strlen(key), NULL);
-
- switch (sqlite3_step(stmt)) {
- case SQLITE_ROW:
- if (lk) {
- s = strlcpy(lk->userinfo.username, sqlite3_column_text(stmt, 0),
- sizeof(lk->userinfo.username));
- if (s >= sizeof(lk->userinfo.username))
- goto error;
- lk->userinfo.uid = sqlite3_column_int(stmt, 1);
- lk->userinfo.gid = sqlite3_column_int(stmt, 2);
- s = strlcpy(lk->userinfo.directory, sqlite3_column_text(stmt, 3),
- sizeof(lk->userinfo.directory));
- if (s >= sizeof(lk->userinfo.directory))
- goto error;
- }
- sqlite3_finalize(stmt);
- return 1;
+ r = sqlite3_step(stmt);
+ sqlite3_reset(stmt);
- case SQLITE_DONE:
- sqlite3_finalize(stmt);
- return 0;
+ if (r == SQLITE_ROW)
+ return (1);
- default:
- goto error;
- }
+ if (r == SQLITE_DONE)
+ return (0);
-error:
- sqlite3_finalize(stmt);
- return -1;
+ return (-1);
}
static int
-table_sqlite_credentials(struct table_sqlite_handle *tsh, const char *key, union lookup *lk)
+table_sqlite_lookup(int service, const char *key, char *dst, size_t sz)
{
- struct table *cfg = table_find(tsh->table->t_name, "conf");
- const char *query = table_get(cfg, "query_credentials");
- sqlite3_stmt *stmt;
- size_t s;
-
- if (query == NULL) {
- log_warnx("table_sqlite: lookup: no query configured for credentials");
- return -1;
+ sqlite3_stmt *stmt;
+ const char *value;
+ int r, s;
+
+ stmt = table_sqlite_query(key, service);
+ if (stmt == NULL)
+ return (-1);
+
+ s = sqlite3_step(stmt);
+ if (s == SQLITE_DONE) {
+ sqlite3_reset(stmt);
+ return (0);
}
- if (sqlite3_prepare_v2(tsh->ppDb, query, -1, &stmt, 0) != SQLITE_OK) {
- log_warnx("table_sqlite: prepare: %s", sqlite3_errmsg(tsh->ppDb));
- return -1;
+ if (s != SQLITE_ROW) {
+ log_warnx("table-sqlite: sqlite3_step: %s",
+ sqlite3_errmsg(db));
+ sqlite3_reset(stmt);
+ return (-1);
}
- if (sqlite3_column_count(stmt) != 2) {
- log_warnx("table_sqlite: columns: invalid resultset");
- sqlite3_finalize(stmt);
- return -1;
- }
+ r = 1;
- sqlite3_bind_text(stmt, 1, key, strlen(key), NULL);
- switch (sqlite3_step(stmt)) {
- case SQLITE_ROW:
- if (lk) {
- s = strlcpy(lk->creds.username, sqlite3_column_text(stmt, 0),
- sizeof(lk->creds.username));
- if (s >= sizeof(lk->creds.username))
- goto error;
- s = strlcpy(lk->creds.password, sqlite3_column_text(stmt, 1),
- sizeof(lk->creds.password));
- if (s >= sizeof(lk->creds.password))
- goto error;
+ switch(service) {
+ case K_ALIAS:
+ do {
+ value = sqlite3_column_text(stmt, 0);
+ if (dst[0] && strlcat(dst, ", ", sz) >= sz) {
+ log_warnx("warn: table-sqlite: result too large");
+ r = -1;
+ break;
+ }
+ if (strlcat(dst, value, sz) >= sz) {
+ log_warnx("warn: table-sqlite: result too large");
+ r = -1;
+ break;
+ }
+ s = sqlite3_step(stmt);
+ } while (s == SQLITE_ROW);
+
+ if (s != SQLITE_ROW && s != SQLITE_DONE) {
+ log_warnx("table-sqlite: sqlite3_step: %s",
+ sqlite3_errmsg(db));
+ r = -1;
}
- sqlite3_finalize(stmt);
- return 1;
-
- case SQLITE_DONE:
- sqlite3_finalize(stmt);
- return 0;
-
+ break;
+ case K_CREDENTIALS:
+ if (snprintf(dst, sz, "%s:%s",
+ sqlite3_column_text(stmt, 0),
+ sqlite3_column_text(stmt, 1)) > (ssize_t)sz) {
+ log_warnx("warn: table-sqlite: result too large");
+ r = -1;
+ }
+ break;
+ case K_USERINFO:
+ if (snprintf(dst, sz, "%s:%i:%i:%s",
+ sqlite3_column_text(stmt, 0),
+ sqlite3_column_int(stmt, 1),
+ sqlite3_column_int(stmt, 2),
+ sqlite3_column_text(stmt, 3)) > (ssize_t)sz) {
+ log_warnx("warn: table-sqlite: result too large");
+ r = -1;
+ }
+ break;
+ case K_DOMAIN:
+ case K_NETADDR:
+ case K_SOURCE:
+ case K_MAILADDR:
+ case K_ADDRNAME:
+ if (strlcpy(dst, sqlite3_column_text(stmt, 0), sz) >= sz) {
+ log_warnx("warn: table-sqlite: result too large");
+ r = -1;
+ }
+ break;
default:
- goto error;
+ log_warnx("warn: table-sqlite: unknown service %i", service);
+ r = -1;
}
-error:
- sqlite3_finalize(stmt);
- return -1;
+ return (r);
}
-
static int
-table_sqlite_netaddr(struct table_sqlite_handle *tsh, const char *key, union lookup *lk)
+table_sqlite_fetch(int service, char *dst, size_t sz)
{
- struct table *cfg = table_find(tsh->table->t_name, "conf");
- const char *query = table_get(cfg, "query_netaddr");
- sqlite3_stmt *stmt;
-
- if (query == NULL) {
- log_warnx("table_sqlite: lookup: no query configured for netaddr");
- return -1;
- }
+ const char *k;
+ int s;
- if (sqlite3_prepare_v2(tsh->ppDb, query, -1, &stmt, 0) != SQLITE_OK) {
- log_warnx("table_sqlite: prepare: %s", sqlite3_errmsg(tsh->ppDb));
- return -1;
- }
+ if (service != K_SOURCE)
+ return (-1);
- if (sqlite3_column_count(stmt) != 1) {
- log_warnx("table_sqlite: columns: invalid resultset");
- sqlite3_finalize(stmt);
- return -1;
- }
+ if (stmt_fetch_source == NULL)
+ return (-1);
- sqlite3_bind_text(stmt, 1, key, strlen(key), NULL);
- switch (sqlite3_step(stmt)) {
- case SQLITE_ROW:
- if (lk) {
- if (! text_to_netaddr(&lk->netaddr, sqlite3_column_text(stmt, 0)))
- goto error;
- }
- sqlite3_finalize(stmt);
- return 1;
+ if (source_ncall < source_refresh &&
+ time(NULL) - source_update < source_expire)
+ goto fetch;
- case SQLITE_DONE:
- sqlite3_finalize(stmt);
- return 0;
+ source_iter = NULL;
+ while(dict_poproot(&sources, NULL, NULL))
+ ;
- default:
- goto error;
+ while ((s = sqlite3_step(stmt_fetch_source)) == SQLITE_ROW)
+ dict_set(&sources, sqlite3_column_text(stmt_fetch_source, 0), NULL);
+
+ if (s != SQLITE_DONE)
+ log_warnx("warn: table-sqlite: sqlite3_step: %s",
+ sqlite3_errmsg(db));
+
+ sqlite3_reset(stmt_fetch_source);
+
+ source_update = time(NULL);
+ source_ncall = 0;
+
+ fetch:
+
+ source_ncall += 1;
+
+ if (! dict_iter(&sources, &source_iter, &k, (void **)NULL)) {
+ source_iter = NULL;
+ if (! dict_iter(&sources, &source_iter, &k, (void **)NULL))
+ return (0);
}
-error:
- sqlite3_finalize(stmt);
- return -1;
+ if (strlcpy(dst, k, sz) >= sz)
+ return (-1);
+
+ return (1);
}