diff options
author | Eric Faurot <eric@cvs.openbsd.org> | 2014-02-04 13:55:35 +0000 |
---|---|---|
committer | Eric Faurot <eric@cvs.openbsd.org> | 2014-02-04 13:55:35 +0000 |
commit | 75fc84794f58dbf709e6cc34d5fb7524930d108f (patch) | |
tree | 9e37af0da927e2c78efee87a28b947bfe99866cf | |
parent | 5466a3045acfc02b1542c40152b69df386bcf9e0 (diff) |
socketmap table backend.
-rw-r--r-- | usr.sbin/smtpd/smtpd-api.h | 8 | ||||
-rw-r--r-- | usr.sbin/smtpd/table_api.c | 20 | ||||
-rw-r--r-- | usr.sbin/smtpd/table_proc.c | 13 | ||||
-rw-r--r-- | usr.sbin/smtpd/table_socketmap.c | 261 |
4 files changed, 291 insertions, 11 deletions
diff --git a/usr.sbin/smtpd/smtpd-api.h b/usr.sbin/smtpd/smtpd-api.h index d2bc18b1ae1..bb155a0da76 100644 --- a/usr.sbin/smtpd/smtpd-api.h +++ b/usr.sbin/smtpd/smtpd-api.h @@ -1,4 +1,4 @@ -/* $OpenBSD: smtpd-api.h,v 1.13 2013/12/05 09:26:47 eric Exp $ */ +/* $OpenBSD: smtpd-api.h,v 1.14 2014/02/04 13:55:34 eric Exp $ */ /* * Copyright (c) 2013 Eric Faurot <eric@openbsd.org> @@ -185,6 +185,11 @@ struct scheduler_batch { #define PROC_TABLE_API_VERSION 1 +struct table_open_params { + uint32_t version; + char name[SMTPD_MAXLINESIZE]; +}; + enum table_service { K_NONE = 0x00, K_ALIAS = 0x01, /* returns struct expand */ @@ -298,6 +303,7 @@ void table_api_on_check(int(*)(int, const char *)); void table_api_on_lookup(int(*)(int, const char *, char *, size_t)); void table_api_on_fetch(int(*)(int, char *, size_t)); int table_api_dispatch(void); +const char *table_api_get_name(void); /* tree.c */ #define tree_init(t) do { SPLAY_INIT(&((t)->tree)); (t)->count = 0; } while(0) diff --git a/usr.sbin/smtpd/table_api.c b/usr.sbin/smtpd/table_api.c index e2ad7339f2d..501053ce2d0 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.3 2013/10/26 12:27:59 eric Exp $ */ +/* $OpenBSD: table_api.c,v 1.4 2014/02/04 13:55:34 eric Exp $ */ /* * Copyright (c) 2013 Eric Faurot <eric@openbsd.org> @@ -44,6 +44,8 @@ static struct imsg imsg; static size_t rlen; static char *rdata; static struct ibuf *buf; +static char *name; + #if 0 static char *rootpath; static char *user = SMTPD_USER; @@ -102,19 +104,23 @@ table_msg_close(void) static void table_msg_dispatch(void) { - uint32_t version; + struct table_open_params op; char res[4096]; int type, r; switch (imsg.hdr.type) { case PROC_TABLE_OPEN: - table_msg_get(&version, sizeof(version)); + table_msg_get(&op, sizeof op); table_msg_end(); - if (version != PROC_TABLE_API_VERSION) { + if (op.version != PROC_TABLE_API_VERSION) { log_warnx("warn: table-api: bad API version"); fatalx("table-api: terminating"); } + if ((name = strdup(op.name)) == NULL) { + log_warn("warn: table-api"); + fatalx("table-api: terminating"); + } imsg_compose(&ibuf, PROC_TABLE_OK, 0, 0, -1, NULL, 0); break; @@ -228,6 +234,12 @@ table_api_on_fetch(int(*cb)(int, char *, size_t)) handler_fetch = cb; } +const char * +table_api_get_name(void) +{ + return name; +} + int table_api_dispatch(void) { diff --git a/usr.sbin/smtpd/table_proc.c b/usr.sbin/smtpd/table_proc.c index 908e4d773c5..d02f76433c5 100644 --- a/usr.sbin/smtpd/table_proc.c +++ b/usr.sbin/smtpd/table_proc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: table_proc.c,v 1.1 2013/07/19 19:53:33 eric Exp $ */ +/* $OpenBSD: table_proc.c,v 1.2 2014/02/04 13:55:34 eric Exp $ */ /* * Copyright (c) 2013 Eric Faurot <eric@openbsd.org> @@ -120,9 +120,9 @@ static void * table_proc_open(struct table *table) { int sp[2]; - uint32_t version; struct table_proc_priv *priv; char *environ_new[2]; + struct table_open_params op; errno = 0; @@ -130,7 +130,7 @@ table_proc_open(struct table *table) log_warn("warn: table-proc: socketpair"); return (NULL); } - priv = calloc(1, sizeof(*priv)); + priv = xcalloc(1, sizeof(*priv), "table_proc_open"); if ((priv->pid = fork()) == -1) { log_warn("warn: table-proc: fork"); @@ -155,9 +155,10 @@ table_proc_open(struct table *table) close(sp[0]); imsg_init(&priv->ibuf, sp[1]); - version = PROC_TABLE_API_VERSION; - imsg_compose(&priv->ibuf, PROC_TABLE_OPEN, 0, 0, -1, - &version, sizeof(version)); + memset(&op, 0, sizeof op); + op.version = PROC_TABLE_API_VERSION; + (void)strlcpy(op.name, table->t_name, sizeof op.name); + imsg_compose(&priv->ibuf, PROC_TABLE_OPEN, 0, 0, -1, &op, sizeof op); table_proc_call(priv); table_proc_end(); diff --git a/usr.sbin/smtpd/table_socketmap.c b/usr.sbin/smtpd/table_socketmap.c new file mode 100644 index 00000000000..123a6b157dd --- /dev/null +++ b/usr.sbin/smtpd/table_socketmap.c @@ -0,0 +1,261 @@ +/* $OpenBSD: table_socketmap.c,v 1.1 2014/02/04 13:55:34 eric Exp $ */ + +/* + * 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 + * 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 <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + +#include "smtpd-defines.h" +#include "smtpd-api.h" +#include "log.h" + +static int table_socketmap_update(void); +static int table_socketmap_lookup(int, const char *, char *, size_t); +static int table_socketmap_check(int, const char *); +static int table_socketmap_fetch(int, char *, size_t); + +static int table_socketmap_connect(const char *); + +static char *config; +static int sock = -1; +static FILE *sockstream; +#define REPLYBUFFERSIZE 100000 +static char repbuffer[REPLYBUFFERSIZE+1]; + +enum socketmap_reply{ + SM_OK = 0, + SM_NOTFOUND, + SM_TEMP, + SM_TIMEOUT, + SM_PERM, +}; + +int +main(int argc, char **argv) +{ + int ch; + + log_init(1); + log_verbose(~0); + + while ((ch = getopt(argc, argv, "")) != -1) { + switch (ch) { + default: + log_warnx("warn: table-socketmap: bad option"); + return (1); + /* NOTREACHED */ + } + } + argc -= optind; + argv += optind; + + if (argc != 1) { + log_warnx("warn: table-socketmap: bogus argument(s)"); + return (1); + } + + config = argv[0]; + + if (table_socketmap_connect(config) == 0) { + log_warnx("warn: table-socketmap: error connecting to %s", config); + return (1); + } + + table_api_on_update(table_socketmap_update); + table_api_on_check(table_socketmap_check); + table_api_on_lookup(table_socketmap_lookup); + table_api_on_fetch(table_socketmap_fetch); + table_api_dispatch(); + + return (0); +} + +static int +table_socketmap_connect(const char *s) +{ + struct sockaddr_un sun; + + if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + log_warn("warn: table-socketmap"); + goto err; + } + + memset(&sun, 0, sizeof sun); + sun.sun_family = AF_UNIX; + if (strlcpy(sun.sun_path, s, sizeof(sun.sun_path)) >= + sizeof(sun.sun_path)) { + log_warnx("warn: table-socketmap: socket path too long"); + goto err; + } + + if (connect(sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) { + log_warn("warn: table-socketmap"); + goto err; + } + + if ((sockstream = fdopen(sock, "w+")) == NULL) { + log_warn("warn: table-socketmap"); + goto err; + } + + return 1; + +err: + if (sock) { + close(sock); + sock = -1; + } + return 0; +} + +enum socketmap_reply +table_socketmap_query(const char *name, const char *key) +{ + char *buf, *lbuf = NULL; + size_t len; + int ret = SM_PERM; + + memset(repbuffer, 0, sizeof repbuffer); + fprintf(sockstream, "%s %s\n", name, key); + fflush(sockstream); + + buf = fgetln(sockstream, &len); + if (buf == NULL) { + log_warnx("warn: table-socketmap: socketmap has lost its socket"); + strlcpy(repbuffer, "lost connection to socket", sizeof repbuffer); + ret = SM_PERM; + goto err; + } + if (buf[len - 1] == '\n') + buf[len - 1] = '\0'; + else { + if ((lbuf = malloc(len + 1)) == NULL) { + log_warnx("warn: table-socketmap: memory exhaustion"); + strlcpy(repbuffer, "memory exhaustion", sizeof repbuffer); + ret = SM_PERM; + goto err; + } + memcpy(lbuf, buf, len); + lbuf[len] = '\0'; + buf = lbuf; + } + free(lbuf); + lbuf = NULL; + + if (strlcpy(repbuffer, buf, sizeof repbuffer) >= sizeof repbuffer) { + log_warnx("warn: table-socketmap: socketmap reply too large (>%d bytes)", + sizeof repbuffer); + strlcpy(repbuffer, "socketmap reply too large (>%d bytes)", sizeof repbuffer); + ret = SM_PERM; + goto err; + } + + if (strncasecmp(repbuffer, "OK ", 3) == 0) { + ret = SM_OK; + memmove(repbuffer, repbuffer+3, strlen(repbuffer)-2); + } + else if (strncasecmp(repbuffer, "NOTFOUND ", 9) == 0) { + ret = SM_NOTFOUND; + memmove(repbuffer, repbuffer+9, strlen(repbuffer)-8); + } + else if (strncasecmp(repbuffer, "TEMP ", 5) == 0) { + ret = SM_TEMP; + memmove(repbuffer, repbuffer+5, strlen(repbuffer)-4); + } + else if (strncasecmp(repbuffer, "TIMEOUT ", 8) == 0) { + ret = SM_TIMEOUT; + memmove(repbuffer, repbuffer+8, strlen(repbuffer)-7); + } + else if (strncasecmp(repbuffer, "PERM ", 5) == 0) { + ret = SM_PERM; + memmove(repbuffer, repbuffer+5, strlen(repbuffer)-4); + } + else { + ret = SM_PERM; + strlcpy(repbuffer, "unrecognized socketmap reply", sizeof repbuffer); + } + +err: + if (lbuf) + free(lbuf); + return ret; +} + +static int +table_socketmap_update(void) +{ + return 1; +} + +static int +table_socketmap_check(int service, const char *key) +{ + return (-1); +} + +static int +table_socketmap_lookup(int service, const char *key, char *dst, size_t sz) +{ + int r; + enum socketmap_reply rep; + + rep = table_socketmap_query(table_api_get_name(), key); + if (rep == SM_NOTFOUND) + return 0; + if (rep != SM_OK) { + log_warnx("warn: table-socketmap: %s", repbuffer); + return -1; + } + if (strlcpy(dst, repbuffer, sz) >= sz) { + log_warnx("warn: table-socketmap: result too large"); + return -1; + } + + r = 1; + switch(service) { + case K_ALIAS: + case K_CREDENTIALS: + case K_USERINFO: + case K_DOMAIN: + case K_NETADDR: + case K_SOURCE: + case K_MAILADDR: + case K_ADDRNAME: + break; + default: + log_warnx("warn: table-socketmap: unknown service %d", service); + r = -1; + } + + return (r); +} + +static int +table_socketmap_fetch(int service, char *key, size_t sz) +{ + return (-1); +} |