Hi, I've attached a slightly updated patch for the procexec. Ping for someone to take a look :)
Cheers, Aisha 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..debfc8d8ab7 100644 --- a/usr.sbin/smtpd/smtpd/Makefile +++ b/usr.sbin/smtpd/smtpd/Makefile @@ -63,6 +63,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 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..88bfc435fb3 --- /dev/null +++ b/usr.sbin/smtpd/table_procexec.c @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2013 Eric Faurot <e...@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; +}; + +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("procexec - socket pair: %s", t->t_name); + } + + pe_handle = xcalloc(1, sizeof(*pe_handle)); + + 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->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] != '/') + fatalx("procexec - config needs absolute path: %s", t->t_name); + execr = snprintf(exec, sizeof(exec), "exec %s" , t->t_config); + if (execr >= (int) sizeof(exec)) + fatalx("procexec - execr: %s", t->t_name); + execl("/bin/sh", "/bin/sh", "-c", exec, (char *)NULL); + fatalx("procexec: %s", t->t_name); + } +} + +static void +table_procexec_close(struct table *t){ + if(t->t_handle == NULL) + return; + 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; +}