A very small change with fixing an off by one copy to the return value.
It was also copying the '\n' character by mistake.
diff --git a/usr.sbin/smtpd/parse.y b/usr.sbin/smtpd/parse.y
index 832f4f2aec9..ff7b9a9a340 100644
--- a/usr.sbin/smtpd/parse.y
+++ b/usr.sbin/smtpd/parse.y
@@ -2543,13 +2543,6 @@ table : TABLE STRING STRING {
config = p+1;
}
}
- if (config != NULL && *config != '/') {
- yyerror("invalid backend parameter for table:
%s",
- $2);
- free($2);
- free($3);
- YYERROR;
- }
table = table_create(conf, backend, $2, config);
if (!table_config(table)) {
yyerror("invalid configuration file %s for
table %s",
diff --git a/usr.sbin/smtpd/smtpctl/Makefile b/usr.sbin/smtpd/smtpctl/Makefile
index ef8148be8c9..46831d647dc 100644
--- a/usr.sbin/smtpd/smtpctl/Makefile
+++ b/usr.sbin/smtpd/smtpctl/Makefile
@@ -47,7 +47,7 @@ SRCS+= table.c
SRCS+= table_static.c
SRCS+= table_db.c
SRCS+= table_getpwnam.c
-SRCS+= table_proc.c
+SRCS+= table_procexec.c
SRCS+= unpack_dns.c
SRCS+= spfwalk.c
diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h
index e6fc114d0a6..8ef80add4e7 100644
--- a/usr.sbin/smtpd/smtpd.h
+++ b/usr.sbin/smtpd/smtpd.h
@@ -1663,6 +1663,7 @@ int table_regex_match(const char *, const char *);
void table_open_all(struct smtpd *);
void table_dump_all(struct smtpd *);
void table_close_all(struct smtpd *);
+const char *table_service_name(enum table_service );
/* to.c */
diff --git a/usr.sbin/smtpd/smtpd/Makefile b/usr.sbin/smtpd/smtpd/Makefile
index b31d4e42224..64e73c3bb70 100644
--- a/usr.sbin/smtpd/smtpd/Makefile
+++ b/usr.sbin/smtpd/smtpd/Makefile
@@ -62,7 +62,7 @@ SRCS+= compress_gzip.c
SRCS+= table_db.c
SRCS+= table_getpwnam.c
-SRCS+= table_proc.c
+SRCS+= table_procexec.c
SRCS+= table_static.c
SRCS+= queue_fs.c
diff --git a/usr.sbin/smtpd/table.c b/usr.sbin/smtpd/table.c
index 7328cf5df6e..81102ef90e1 100644
--- a/usr.sbin/smtpd/table.c
+++ b/usr.sbin/smtpd/table.c
@@ -35,9 +35,8 @@ struct table_backend *table_backend_lookup(const char *);
extern struct table_backend table_backend_static;
extern struct table_backend table_backend_db;
extern struct table_backend table_backend_getpwnam;
-extern struct table_backend table_backend_proc;
+extern struct table_backend table_backend_procexec;
-static const char * table_service_name(enum table_service);
static int table_parse_lookup(enum table_service, const char *, const char *,
union lookup *);
static int parse_sockaddr(struct sockaddr *, int, const char *);
@@ -48,7 +47,7 @@ static struct table_backend *backends[] = {
&table_backend_static,
&table_backend_db,
&table_backend_getpwnam,
- &table_backend_proc,
+ &table_backend_procexec,
NULL
};
@@ -67,7 +66,7 @@ table_backend_lookup(const char *backend)
return NULL;
}
-static const char *
+const char *
table_service_name(enum table_service s)
{
switch (s) {
@@ -198,10 +197,9 @@ table_create(struct smtpd *conf, const char *backend,
const char *name,
PATH_LIBEXEC"/table-%s\"", backend);
}
if (stat(path, &sb) == 0) {
- tb = table_backend_lookup("proc");
- (void)strlcpy(path, backend, sizeof(path));
+ tb = table_backend_lookup("proc-exec");
if (config) {
- (void)strlcat(path, ":", sizeof(path));
+ (void)strlcat(path, " ", sizeof(path));
if (strlcat(path, config, sizeof(path))
>= sizeof(path))
fatalx("table_create: config file path
too long");
diff --git a/usr.sbin/smtpd/table_proc.c b/usr.sbin/smtpd/table_proc.c
deleted file mode 100644
index 56893a0fb61..00000000000
--- a/usr.sbin/smtpd/table_proc.c
+++ /dev/null
@@ -1,265 +0,0 @@
-/* $OpenBSD: table_proc.c,v 1.17 2021/06/14 17:58:16 eric Exp $ */
-
-/*
- * Copyright (c) 2013 Eric Faurot <[email protected]>
- *
- * 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 <errno.h>
-#include <string.h>
-
-#include "smtpd.h"
-#include "log.h"
-
-struct table_proc_priv {
- pid_t pid;
- struct imsgbuf ibuf;
-};
-
-static struct imsg imsg;
-static size_t rlen;
-static char *rdata;
-
-extern char **environ;
-
-static void
-table_proc_call(struct table_proc_priv *p)
-{
- ssize_t n;
-
- if (imsg_flush(&p->ibuf) == -1) {
- log_warn("warn: table-proc: imsg_flush");
- fatalx("table-proc: exiting");
- }
-
- while (1) {
- if ((n = imsg_get(&p->ibuf, &imsg)) == -1) {
- log_warn("warn: table-proc: imsg_get");
- break;
- }
- if (n) {
- rlen = imsg.hdr.len - IMSG_HEADER_SIZE;
- rdata = imsg.data;
-
- if (imsg.hdr.type != PROC_TABLE_OK) {
- log_warnx("warn: table-proc: bad response");
- break;
- }
- return;
- }
-
- if ((n = imsg_read(&p->ibuf)) == -1 && errno != EAGAIN) {
- log_warn("warn: table-proc: imsg_read");
- break;
- }
-
- if (n == 0) {
- log_warnx("warn: table-proc: pipe closed");
- break;
- }
- }
-
- fatalx("table-proc: exiting");
-}
-
-static void
-table_proc_read(void *dst, size_t len)
-{
- if (len > rlen) {
- log_warnx("warn: table-proc: bad msg len");
- fatalx("table-proc: exiting");
- }
-
- if (dst)
- memmove(dst, rdata, len);
-
- rlen -= len;
- rdata += len;
-}
-
-static void
-table_proc_end(void)
-{
- if (rlen) {
- log_warnx("warn: table-proc: bogus data");
- fatalx("table-proc: exiting");
- }
- imsg_free(&imsg);
-}
-
-/*
- * API
- */
-
-static int
-table_proc_open(struct table *table)
-{
- struct table_proc_priv *priv;
- struct table_open_params op;
- int fd;
-
- priv = xcalloc(1, sizeof(*priv));
-
- fd = fork_proc_backend("table", table->t_config, table->t_name);
- if (fd == -1)
- fatalx("table-proc: exiting");
-
- imsg_init(&priv->ibuf, fd);
-
- 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();
-
- table->t_handle = priv;
-
- return (1);
-}
-
-static int
-table_proc_update(struct table *table)
-{
- struct table_proc_priv *priv = table->t_handle;
- int r;
-
- imsg_compose(&priv->ibuf, PROC_TABLE_UPDATE, 0, 0, -1, NULL, 0);
-
- table_proc_call(priv);
- table_proc_read(&r, sizeof(r));
- table_proc_end();
-
- return (r);
-}
-
-static void
-table_proc_close(struct table *table)
-{
- struct table_proc_priv *priv = table->t_handle;
-
- imsg_compose(&priv->ibuf, PROC_TABLE_CLOSE, 0, 0, -1, NULL, 0);
- if (imsg_flush(&priv->ibuf) == -1)
- fatal("imsg_flush");
-
- table->t_handle = NULL;
-}
-
-static int
-imsg_add_params(struct ibuf *buf)
-{
- size_t count = 0;
-
- if (imsg_add(buf, &count, sizeof(count)) == -1)
- return (-1);
-
- return (0);
-}
-
-static int
-table_proc_lookup(struct table *table, enum table_service s, const char *k,
char **dst)
-{
- struct table_proc_priv *priv = table->t_handle;
- struct ibuf *buf;
- int r;
-
- buf = imsg_create(&priv->ibuf,
- dst ? PROC_TABLE_LOOKUP : PROC_TABLE_CHECK, 0, 0,
- sizeof(s) + strlen(k) + 1);
-
- if (buf == NULL)
- return (-1);
- if (imsg_add(buf, &s, sizeof(s)) == -1)
- return (-1);
- if (imsg_add_params(buf) == -1)
- return (-1);
- if (imsg_add(buf, k, strlen(k) + 1) == -1)
- return (-1);
- imsg_close(&priv->ibuf, buf);
-
- table_proc_call(priv);
- table_proc_read(&r, sizeof(r));
-
- if (r == 1 && dst) {
- if (rlen == 0) {
- log_warnx("warn: table-proc: empty response");
- fatalx("table-proc: exiting");
- }
- if (rdata[rlen - 1] != '\0') {
- log_warnx("warn: table-proc: not NUL-terminated");
- fatalx("table-proc: exiting");
- }
- *dst = strdup(rdata);
- if (*dst == NULL)
- r = -1;
- table_proc_read(NULL, rlen);
- }
-
- table_proc_end();
-
- return (r);
-}
-
-static int
-table_proc_fetch(struct table *table, enum table_service s, char **dst)
-{
- struct table_proc_priv *priv = table->t_handle;
- struct ibuf *buf;
- int r;
-
- buf = imsg_create(&priv->ibuf, PROC_TABLE_FETCH, 0, 0, sizeof(s));
- if (buf == NULL)
- return (-1);
- if (imsg_add(buf, &s, sizeof(s)) == -1)
- return (-1);
- if (imsg_add_params(buf) == -1)
- return (-1);
- imsg_close(&priv->ibuf, buf);
-
- table_proc_call(priv);
- table_proc_read(&r, sizeof(r));
-
- if (r == 1) {
- if (rlen == 0) {
- log_warnx("warn: table-proc: empty response");
- fatalx("table-proc: exiting");
- }
- if (rdata[rlen - 1] != '\0') {
- log_warnx("warn: table-proc: not NUL-terminated");
- fatalx("table-proc: exiting");
- }
- *dst = strdup(rdata);
- if (*dst == NULL)
- r = -1;
- table_proc_read(NULL, rlen);
- }
-
- table_proc_end();
-
- return (r);
-}
-
-struct table_backend table_backend_proc = {
- "proc",
- K_ANY,
- NULL,
- NULL,
- NULL,
- table_proc_open,
- table_proc_update,
- table_proc_close,
- table_proc_lookup,
- table_proc_fetch,
-};
diff --git a/usr.sbin/smtpd/table_procexec.c b/usr.sbin/smtpd/table_procexec.c
new file mode 100644
index 00000000000..7c7541f5dd9
--- /dev/null
+++ b/usr.sbin/smtpd/table_procexec.c
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 2013 Eric Faurot <[email protected]>
+ *
+ * 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/queue.h>
+#include <sys/tree.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <event.h>
+#include <fcntl.h>
+#include <imsg.h>
+#include <paths.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <unistd.h>
+
+#include <err.h>
+#include <inttypes.h>
+
+#include "smtpd.h"
+#include "log.h"
+
+#define PROCEXEC_VERSION "1"
+#define PROCEXEC_TIMEOUT 500
+
+static int table_procexec_open(struct table *);
+static int table_procexec_update(struct table *);
+static void table_procexec_close(struct table *);
+static int table_procexec_lookup(struct table *, enum table_service, const
char *, char **);
+static int table_procexec_fetch(struct table *, enum table_service, char **);
+
+enum procexec_query;
+static int
+table_procexec_helper(struct table *, enum procexec_query, enum table_service,
const char *, char **);
+
+struct table_backend table_backend_procexec = {
+ "proc-exec",
+ K_ANY,
+ NULL,
+ NULL,
+ NULL,
+ table_procexec_open,
+ table_procexec_update,
+ table_procexec_close,
+ table_procexec_lookup,
+ table_procexec_fetch,
+};
+
+struct procexec_handle {
+ FILE *backend_w;
+ FILE *backend_r;
+ int read_fd;
+ pid_t pid;
+ int status;
+ useconds_t msec;
+};
+
+enum procexec_query {
+ T_UPDATE,
+ T_LOOKUP,
+ T_FETCH
+};
+
+static int
+table_procexec_update(struct table *t) {
+ return table_procexec_helper(t, T_UPDATE, (0), NULL, NULL);
+}
+
+static int
+table_procexec_lookup(struct table *t, enum table_service service, const char
*key, char **dst) {
+ return table_procexec_helper(t, T_LOOKUP, service, key, dst);
+}
+
+static int
+table_procexec_fetch(struct table *t, enum table_service service, char **dst){
+ return table_procexec_helper(t, T_FETCH, service, NULL, dst);
+}
+
+static void
+table_set_ready(int fd, short evt, void *arg){
+ char *line = NULL;
+ size_t len = 0;
+ ssize_t nchar;
+
+ struct procexec_handle *pe_handle = (struct procexec_handle *)arg;
+
+ nchar = getline(&line, &len, pe_handle->backend_r);
+
+ if(nchar <= 15 || strncmp(line, "TABLE-INIT|READY", 16) != 0){
+ pe_handle->status = -1;
+ }
+ else{
+ pe_handle->status = 1;
+ }
+ free(line);
+}
+
+static int
+table_procexec_open(struct table *t) {
+ struct procexec_handle *pe_handle;
+ pid_t pid;
+ int sp[2];
+
+ pe_handle = xcalloc(1, sizeof(*pe_handle));
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, sp) == -1){
+ fatalx("procexec - socket pair: %s", t->t_name);
+ }
+
+ if ((pid = fork()) == -1) {
+ fatalx("procexec - fork: %s", t->t_name);
+ }
+
+ if (pid > 0) {
+ close(sp[0]);
+ FILE *backend_w, *backend_r;
+ if ((backend_w = fdopen(sp[1], "w")) == NULL)
+ fatalx("procexec - backend_w: %s", t->t_name);
+
+ if ((backend_r = fdopen(sp[1], "r")) == NULL)
+ fatalx("procexec - backend_r: %s", t->t_name);
+ pe_handle->read_fd = sp[1];
+
+ pe_handle->pid = pid;
+ pe_handle->backend_w = backend_w;
+ pe_handle->backend_r = backend_r;
+ pe_handle->status = 0;
+ pe_handle->msec = PROCEXEC_TIMEOUT;
+ t->t_handle = pe_handle;
+
+ fprintf(backend_w, "TABLE-INIT|%s|%d\n", PROCEXEC_VERSION,
PROCEXEC_TIMEOUT);
+ fflush(backend_w);
+
+ struct event *ev = (struct event *)xcalloc(1, sizeof(struct
event));
+ event_set(ev, sp[1], EV_READ, table_set_ready, (void
*)pe_handle);
+ event_add(ev, NULL);
+
+ return 1;
+ }
+ else {
+ close(sp[1]);
+ dup2(sp[0], STDIN_FILENO);
+ dup2(sp[0], STDOUT_FILENO);
+
+ int execr;
+ char exec[_POSIX_ARG_MAX];
+ execr = snprintf(exec, sizeof(exec), "exec %s" , t->t_config);
+ if (execr < 0 || execr >= (int) sizeof(exec))
+ fatalx("procexec - execr: %s", t->t_name);
+ execl("/bin/sh", "/bin/sh", "-c", exec, (char *)NULL);
+ }
+ return 1;
+}
+
+static void
+table_procexec_close(struct table *t) {
+ struct procexec_handle *pe_handle = (struct procexec_handle
*)t->t_handle;
+ fclose(pe_handle->backend_r);
+ fclose(pe_handle->backend_w);
+ close(pe_handle->read_fd);
+ waitpid(pe_handle->pid, 0, 0);
+ free(pe_handle);
+ pe_handle = NULL;
+}
+
+static void
+procexec_clear_io(int fd, short evt, void *arg){
+ char *line;
+ size_t len;
+ ssize_t nchar;
+
+ struct procexec_handle *pe_handle = (struct procexec_handle *)arg;
+
+ line = NULL;
+ len = 0;
+ nchar = getline(&line, &len, pe_handle->backend_r);
+ free(line);
+ pe_handle->status = 1;
+}
+
+static int
+procexec_parse(struct procexec_handle *pe_handle, uint64_t reqid, enum
procexec_query query, char **dst) {
+ char *oline, *line, *tline;
+ size_t len;
+ ssize_t nchar;
+ uint64_t resid;
+
+ oline = NULL;
+ len = 0;
+ struct pollfd pfd = { pe_handle->read_fd, POLLIN, 0 };
+ int ret = 0;
+ ret = poll(&pfd, 1, PROCEXEC_TIMEOUT);
+ if(ret == 1){
+ oline = NULL;
+ len = 0;
+ nchar = getline(&oline, &len, pe_handle->backend_r);
+ }
+ else {
+ log_trace(TRACE_IO, "io: table backend io has timed out");
+ pe_handle->status = -1;
+
+ struct event *ev = (struct event *)xcalloc(1, sizeof(struct
event));
+ event_set(ev, pe_handle->read_fd, EV_READ, procexec_clear_io,
(void *)pe_handle);
+ event_add(ev, NULL);
+
+ goto tempfail;
+ }
+ if (len == 0 || nchar < 0)
+ goto tempfail;
+ line = oline;
+
+ len = strlen(oline);
+ line[len-1] = '\0';
+
+ if(len < 13 || strncmp(line, "TABLE-RESULT|", 13) != 0)
+ goto tempfail;
+ line += 13;
+ len -= 13;
+
+ resid = strtoull(line, &tline, 16);
+ if (len < 17 || *tline != '|')
+ goto tempfail;
+ if (errno == ERANGE && resid == ULLONG_MAX)
+ goto tempfail;
+ if (reqid != resid)
+ goto tempfail;
+ line += 17;
+ len -= 17;
+
+ if(strncmp(line, "NOT-FOUND", 9) == 0)
+ goto failure;
+ if(len < 7 || strncmp(line, "FAILURE", 7) == 0 || strncmp(line,
"SUCCESS", 7) != 0)
+ goto failure;
+ line += 8;
+ len -= 8;
+ switch(query){
+ case T_UPDATE:
+ goto success;
+ break;
+ case T_LOOKUP:
+ case T_FETCH:
+ *dst = xcalloc(len, sizeof(*dst));
+ if (strlcpy(*dst, line, len) >= len){
+ free(*dst);
+ goto tempfail;
+ }
+ goto success;
+ break;
+ }
+
+ failure:
+ free(oline);
+ return 0;
+
+ tempfail:
+ free(oline);
+ return -1;
+
+ success:
+ free(oline);
+ return 1;
+}
+
+static int
+table_procexec_helper(struct table *t, enum procexec_query query, enum
table_service service, const char *key, char **dst) {
+ struct procexec_handle *pe_handle;
+ FILE* backend_w;
+ struct timeval tv;
+ uint64_t reqid;
+
+ pe_handle = (struct procexec_handle *)t->t_handle;
+ if(pe_handle == NULL || pe_handle->status != 1){
+ log_trace(TRACE_IO, "io: table backend io is %s",
(pe_handle->status == -1)?"broken":"not ready");
+ return -1;
+ }
+ backend_w = pe_handle->backend_w;
+
+ reqid = generate_uid();
+ gettimeofday(&tv, NULL);
+
+ switch(query){
+ case T_UPDATE:
+ fprintf(backend_w, "TABLE|%s|%lld.%06ld|UPDATE|%016" PRIx64
"\n",
+ PROCEXEC_VERSION, tv.tv_sec, tv.tv_usec, reqid);
+ fflush(backend_w);
+ return procexec_parse(pe_handle, reqid, query, dst);
+ break;
+ case T_LOOKUP:
+ fprintf(backend_w, "TABLE|%s|%lld.%06ld|LOOKUP|%016" PRIx64
"|%s|%s\n",
+ PROCEXEC_VERSION, tv.tv_sec, tv.tv_usec, reqid,
table_service_name(service), key);
+ fflush(backend_w);
+ return procexec_parse(pe_handle, reqid, query, dst);
+ break;
+ case T_FETCH:
+ fprintf(backend_w, "TABLE|%s|%lld.%06ld|FETCH|%016" PRIx64
"|%s\n",
+ PROCEXEC_VERSION, tv.tv_sec, tv.tv_usec, reqid,
table_service_name(service));
+ fflush(backend_w);
+ return procexec_parse(pe_handle, reqid, query, dst);
+ break;
+ }
+ return -1;
+}