[prev in list] [next in list] [prev in thread] [next in thread] 

List:       openbsd-tech
Subject:    add table_procexec in smtpd
From:       Aisha Tammy <openbsd.tech () aisha ! cc>
Date:       2021-05-31 13:21:12
Message-ID: 20210531132112.cgdci63csj4nao5b () serverNOOB ! epsilonKNOT ! xyz
[Download RAW message or body]

Hi all,
  I've attached a diff to add table_procexec as a table backend
in smtpd(8). This imports the table_procexec from opensmtpd-extras,
which is available upstream but is not present in the port.
I've successfully replaced the standard aliases table

table aliases file:/etc/mail/aliases

with a very simple proof of concept shell script which forwards all
mail to a single account (root@bsd.ac)

table aliases proc-exec:/usr/local/bin/aliases_procexec

The shell script (/usr/local/bin/aliases_procexec) is

#!/bin/ksh

while read line
do
  reqid="$(echo $line | awk -F'|' '{ print $5; }')"
  reply="table-result|$reqid|found|root@bsd.ac"
  echo $reply
done < /dev/stdin
exit 0

The full /etc/mail/smtpd.conf is

#	$OpenBSD: smtpd.conf,v 1.14 2019/11/26 20:14:38 gilles Exp $

# This is the smtpd server system-wide configuration file.
# See smtpd.conf(5) for more information.

table aliases proc-exec:/usr/local/bin/aliases_procexec
listen on socket

# To accept external mail, replace with: listen on all
#
listen on lo0

action "local_mail" mbox alias <aliases>
action "outbound" relay
action "bsd.ac" relay host smtp://10.7.0.1

# Uncomment the following to accept external mail for domain "example.org"
#
# match from any for domain "example.org" action "local_mail"
match from local for local action "local_mail"
match from local for domain "bsd.ac" action "bsd.ac"
match from local for any action "outbound"

This diff is still a very early work, so I'm hoping for comments
to improve the work.

Some points that are still left to do
- document the line protocol in table(5)
- add a better reference implementation, maybe a replacement for aliases
- I've left in the table_procexec_check but commented it out.
  I am unsure if that is needed at all.
- Maybe my method of closing, in table_procexec_close is not the best.

(and maybe more are still left but those can be thought of later)

This is my first diff for anything in base, so I may have made some mistakes.
Comments and improvements would be really nice.

Cheers,
Aisha

PS: I've cc'ed eric@ as this was their original work and I'm just modifying it.


diff --git a/usr.sbin/smtpd/smtpctl/Makefile b/usr.sbin/smtpd/smtpctl/Makefile
index ef8148be8c9..2e8beff1ad1 100644
--- a/usr.sbin/smtpd/smtpctl/Makefile
+++ b/usr.sbin/smtpd/smtpctl/Makefile
@@ -48,6 +48,7 @@ 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 be934112103..221f24fbdc4 100644
--- a/usr.sbin/smtpd/smtpd.h
+++ b/usr.sbin/smtpd/smtpd.h
@@ -1656,6 +1656,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..e2f6e82c6e8 100644
--- a/usr.sbin/smtpd/smtpd/Makefile
+++ b/usr.sbin/smtpd/smtpd/Makefile
@@ -64,6 +64,7 @@ SRCS+=		table_db.c
 SRCS+=		table_getpwnam.c
 SRCS+=		table_proc.c
 SRCS+=		table_static.c
+SRCS+=		table_procexec.c
 
 SRCS+=		queue_fs.c
 SRCS+=		queue_null.c
diff --git a/usr.sbin/smtpd/table.c b/usr.sbin/smtpd/table.c
index 1d82d88b81a..0c67d205065 100644
--- a/usr.sbin/smtpd/table.c
+++ b/usr.sbin/smtpd/table.c
@@ -46,8 +46,8 @@ 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 *);
@@ -59,6 +59,7 @@ static struct table_backend *backends[] = {
 	&table_backend_db,
 	&table_backend_getpwnam,
 	&table_backend_proc,
+	&table_backend_procexec,
 	NULL
 };
 
@@ -77,7 +78,7 @@ table_backend_lookup(const char *backend)
 	return NULL;
 }
 
-static const char *
+const char *
 table_service_name(enum table_service s)
 {
 	switch (s) {
diff --git a/usr.sbin/smtpd/table_procexec.c b/usr.sbin/smtpd/table_procexec.c
new file mode 100644
index 00000000000..269c55ecd9f
--- /dev/null
+++ b/usr.sbin/smtpd/table_procexec.c
@@ -0,0 +1,355 @@
+/*
+ * 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/queue.h>
+#include <sys/tree.h>
+#include <sys/socket.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <event.h>
+#include <fcntl.h>
+#include <imsg.h>
+#include <paths.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 PROTOCOL_VERSION "1"
+
+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 **);
+
+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;
+	pid_t		pid;
+	int		closed;
+};
+
+#define	PATH_LIBEXEC		"/usr/local/libexec/smtpd"
+
+static int
+table_procexec_open(struct table *t) {
+	struct procexec_handle *pe_handle;
+	pid_t pid;
+	int sp[2];
+	int execr;
+	char exec[_POSIX_ARG_MAX];
+
+	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, sp) == -1){
+		fatalx("socket pair: %s", t->t_name);
+	}
+
+	pe_handle = xcalloc(1, sizeof(*pe_handle));
+	pe_handle->closed = 0;
+
+	if ((pid = fork()) == -1) {
+		fatalx("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("backend_w: %s", t->t_name);
+
+		if ((backend_r = fdopen(sp[1], "r")) == NULL)
+			fatalx("backend_r: %s", t->t_name);
+
+		pe_handle->pid = pid;
+		pe_handle->backend_w = backend_w;
+		pe_handle->backend_r = backend_r;
+		t->t_handle = pe_handle;
+		return 1;
+	}
+	else {
+		close(sp[1]);
+		dup2(sp[0], STDIN_FILENO);
+		dup2(sp[0], STDOUT_FILENO);
+
+		if (t->t_config[0] == '/')
+			execr = snprintf(exec, sizeof(exec), "exec %s" , t->t_config);
+		else
+			execr = snprintf(exec, sizeof(exec), "exec %s/%s" , PATH_LIBEXEC, t->t_config);
+		if (execr >= (int) sizeof(exec))
+			fatalx("execr: %s", t->t_name);
+
+		execl("/bin/sh", "/bin/sh", "-c", exec, (char *)NULL);
+		if(((struct procexec_handle *)t->t_handle)->closed == 0)
+			fatalx("procexec: %s", t->t_name);
+		return 0;
+	}
+}
+
+static void
+table_procexec_close(struct table *t){
+	if(t->t_handle == NULL)
+		return;
+	((struct procexec_handle *)t->t_handle)->closed = 1;
+	kill(((struct procexec_handle *)t->t_handle)->pid, SIGTERM);
+	free(t->t_handle);
+	t->t_handle = NULL;
+}
+
+static int
+table_procexec_update(struct table *t)
+{
+	struct timeval tv;
+	uint64_t reqid;
+	char *line = NULL;
+	size_t linecap = 0;
+	ssize_t linelen;
+	uint64_t reqid_res;
+	char *qid = NULL;
+	char *ep = NULL;
+
+	reqid = generate_uid();
+	gettimeofday(&tv, NULL);
+
+	FILE* backend_w = ((struct procexec_handle *)t->t_handle)->backend_w;
+	FILE* backend_r = ((struct procexec_handle *)t->t_handle)->backend_r;
+
+	fprintf(backend_w, "table|%s|%lld.%06ld|update|%016"PRIx64"\n",
+		PROTOCOL_VERSION,
+		tv.tv_sec, tv.tv_usec, reqid);
+	fflush(backend_w);
+
+	linelen = getline(&line, &linecap, backend_r);
+	if (linelen == 0)
+		return 0;
+	line[strcspn(line, "\n")] = '\0';
+
+	if (strncmp(line, "table-result|", 13) != 0)
+		return -1;
+	line += 13;
+
+	qid = line;
+	reqid_res = strtoull(qid, &ep, 16);
+	if (qid[0] == '\0' || *ep != '|')
+		return -1;
+	if (errno == ERANGE && reqid_res == ULLONG_MAX)
+		return -1;
+	if (reqid != reqid_res)
+		return -1;
+
+	line = ep+1;
+
+	return strcmp(line, "updated") == 0;
+}
+
+/*
+static int
+table_procexec_check(int service, struct dict *params, const char *key)
+{
+	struct timeval tv;
+	uint64_t reqid;
+	char *line = NULL;
+	size_t linecap = 0;
+	ssize_t linelen;
+	uint64_t reqid_res;
+	char *qid = NULL;
+	char *ep = NULL;
+
+	reqid = generate_uid();
+	gettimeofday(&tv, NULL);
+
+	fprintf(backend_w, "table|%s|%lld.%06ld|check|%016"PRIx64"|%s|%s\n",
+		PROTOCOL_VERSION,
+		tv.tv_sec, tv.tv_usec, reqid, service_to_name(service), key);
+	fflush(backend_w);
+
+	linelen = getline(&line, &linecap, backend_r);
+	if (linelen == 0)
+		return 0;
+	line[strcspn(line, "\n")] = '\0';
+
+	if (strncmp(line, "table-result|", 13) != 0)
+		return -1;
+	line += 13;
+
+	qid = line;
+	reqid_res = strtoull(qid, &ep, 16);
+	if (qid[0] == '\0' || *ep != '|')
+		return -1;
+	if (errno == ERANGE && reqid_res == ULLONG_MAX)
+		return -1;
+	if (reqid != reqid_res)
+		return -1;
+
+	line = ep+1;
+
+	if (strcmp(line, "failure") == 0)
+		return -1;
+
+	if (strcmp(line, "not-found") == 0)
+		return 0;
+
+	if (strcmp(line, "found") == 0)
+		return 1;
+
+	return -1;
+}
+*/
+
+static int
+table_procexec_lookup(struct table *t, enum table_service service, const char *key, char **dst) {
+	struct timeval tv;
+	uint64_t reqid;
+	char *line = NULL;
+	size_t linecap = 0;
+	ssize_t linelen;
+	uint64_t reqid_res;
+	char *qid = NULL;
+	char *ep = NULL;
+	size_t sz = 0;
+
+	FILE* backend_w = ((struct procexec_handle *)t->t_handle)->backend_w;
+	FILE* backend_r = ((struct procexec_handle *)t->t_handle)->backend_r;
+
+	reqid = generate_uid();
+	gettimeofday(&tv, NULL);
+
+	fprintf(backend_w, "table|%s|%lld.%06ld|lookup|%016"PRIx64"|%s|%s\n",
+		PROTOCOL_VERSION,
+		tv.tv_sec, tv.tv_usec, reqid, table_service_name(service), key);
+	fflush(backend_w);
+
+	linelen = getline(&line, &linecap, backend_r);
+	if (linelen == 0)
+		return 0;
+	line[strcspn(line, "\n")] = '\0';
+
+	if (strncmp(line, "table-result|", 13) != 0)
+		return -1;
+	line += 13;
+
+	qid = line;
+	reqid_res = strtoull(qid, &ep, 16);
+	if (qid[0] == '\0' || *ep != '|')
+		return -1;
+	if (errno == ERANGE && reqid_res == ULLONG_MAX)
+		return -1;
+	if (reqid != reqid_res)
+		return -1;
+
+	line = ep+1;
+
+	if (strcmp(line, "failure") == 0)
+		return -1;
+
+	if (strcmp(line, "not-found") == 0)
+		return 0;
+
+	if (strncmp(line, "found|", 6) == 0) {
+		line = line + 6;
+		sz = strlen(line) + 1;
+		*dst = xcalloc(sz, sizeof(*dst));
+		if (strlcpy(*dst, line, sz) >= sz){
+			free(*dst);
+			return -1;
+		}
+		return 1;
+	}
+	return -1;
+}
+
+static int
+table_procexec_fetch(struct table *t, enum table_service service, char **dst){
+	struct timeval tv;
+	uint64_t reqid;
+	char *line = NULL;
+	size_t linecap = 0;
+	ssize_t linelen;
+	uint64_t reqid_res;
+	char *qid = NULL;
+	char *ep = NULL;
+	size_t sz = 0;
+
+	FILE* backend_w = ((struct procexec_handle *)t->t_handle)->backend_w;
+	FILE* backend_r = ((struct procexec_handle *)t->t_handle)->backend_r;
+
+	reqid = generate_uid();
+	gettimeofday(&tv, NULL);
+
+	fprintf(backend_w, "table|%s|%lld.%06ld|fetch|%016"PRIx64"|%s\n",
+		PROTOCOL_VERSION,
+		tv.tv_sec, tv.tv_usec, reqid, table_service_name(service));
+	fflush(backend_w);
+
+	linelen = getline(&line, &linecap, backend_r);
+	if (linelen == 0)
+		return 0;
+	line[strcspn(line, "\n")] = '\0';
+
+	if (strncmp(line, "table-result|", 13) != 0)
+		return -1;
+	line += 13;
+
+	qid = line;
+	reqid_res = strtoull(qid, &ep, 16);
+	if (qid[0] == '\0' || *ep != '|')
+		return -1;
+	if (errno == ERANGE && reqid_res == ULLONG_MAX)
+		return -1;
+	if (reqid != reqid_res)
+		return -1;
+
+	line = ep+1;
+
+	if (strcmp(line, "failure") == 0)
+		return -1;
+
+	if (strcmp(line, "not-found") == 0)
+		return 0;
+
+	if (strncmp(line, "found|", 6) == 0) {
+		sz = strlen(line) + 1;
+		*dst = xcalloc(sz, sizeof(*dst));
+		if (strlcpy(*dst, line+6, sz) >= sz){
+			free(*dst);
+			return -1;
+		}
+		return 1;
+	}
+	return -1;
+}

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic