xref: /openbsd-src/usr.sbin/smtpd/queue_proc.c (revision bf921b2a265b968a018032bb165729419e711549)
1*bf921b2aSclaudio /*	$OpenBSD: queue_proc.c,v 1.14 2024/11/21 13:42:22 claudio Exp $	*/
23f70ecafSeric 
33f70ecafSeric /*
43f70ecafSeric  * Copyright (c) 2013 Eric Faurot <eric@openbsd.org>
53f70ecafSeric  *
63f70ecafSeric  * Permission to use, copy, modify, and distribute this software for any
73f70ecafSeric  * purpose with or without fee is hereby granted, provided that the above
83f70ecafSeric  * copyright notice and this permission notice appear in all copies.
93f70ecafSeric  *
103f70ecafSeric  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
113f70ecafSeric  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
123f70ecafSeric  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
133f70ecafSeric  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
143f70ecafSeric  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
153f70ecafSeric  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
163f70ecafSeric  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
173f70ecafSeric  */
183f70ecafSeric 
19369c9387Sclaudio #include <errno.h>
203f70ecafSeric #include <fcntl.h>
213f70ecafSeric #include <string.h>
223f70ecafSeric 
233f70ecafSeric #include "smtpd.h"
243f70ecafSeric #include "log.h"
253f70ecafSeric 
263f70ecafSeric static struct imsgbuf	 ibuf;
273f70ecafSeric static struct imsg	 imsg;
283f70ecafSeric static size_t		 rlen;
293f70ecafSeric static char		*rdata;
303f70ecafSeric 
313f70ecafSeric static void
323f70ecafSeric queue_proc_call(void)
333f70ecafSeric {
343f70ecafSeric 	ssize_t	n;
353f70ecafSeric 
36dd7efffeSclaudio 	if (imsgbuf_flush(&ibuf) == -1) {
37dd7efffeSclaudio 		log_warn("warn: queue-proc: imsgbuf_flush");
383f70ecafSeric 		fatalx("queue-proc: exiting");
393f70ecafSeric 	}
403f70ecafSeric 
413f70ecafSeric 	while (1) {
423f70ecafSeric 		if ((n = imsg_get(&ibuf, &imsg)) == -1) {
433f70ecafSeric 			log_warn("warn: queue-proc: imsg_get");
443f70ecafSeric 			break;
453f70ecafSeric 		}
463f70ecafSeric 		if (n) {
473f70ecafSeric 			rlen = imsg.hdr.len - IMSG_HEADER_SIZE;
483f70ecafSeric 			rdata = imsg.data;
493f70ecafSeric 
503f70ecafSeric 			if (imsg.hdr.type != PROC_QUEUE_OK) {
513f70ecafSeric 				log_warnx("warn: queue-proc: bad response");
523f70ecafSeric 				break;
533f70ecafSeric 			}
543f70ecafSeric 			return;
553f70ecafSeric 		}
563f70ecafSeric 
5716b0c81bSclaudio 		if ((n = imsgbuf_read(&ibuf)) == -1) {
58dd7efffeSclaudio 			log_warn("warn: queue-proc: imsgbuf_read");
593f70ecafSeric 			break;
603f70ecafSeric 		}
613f70ecafSeric 
623f70ecafSeric 		if (n == 0) {
633f70ecafSeric 			log_warnx("warn: queue-proc: pipe closed");
643f70ecafSeric 			break;
653f70ecafSeric 		}
663f70ecafSeric 	}
673f70ecafSeric 
683f70ecafSeric 	fatalx("queue-proc: exiting");
693f70ecafSeric }
703f70ecafSeric 
713f70ecafSeric static void
723f70ecafSeric queue_proc_read(void *dst, size_t len)
733f70ecafSeric {
743f70ecafSeric 	if (len > rlen) {
753f70ecafSeric 		log_warnx("warn: queue-proc: bad msg len");
763f70ecafSeric 		fatalx("queue-proc: exiting");
773f70ecafSeric 	}
783f70ecafSeric 
793f70ecafSeric 	memmove(dst, rdata, len);
803f70ecafSeric 	rlen -= len;
813f70ecafSeric 	rdata += len;
823f70ecafSeric }
833f70ecafSeric 
843f70ecafSeric static void
853f70ecafSeric queue_proc_end(void)
863f70ecafSeric {
873f70ecafSeric 	if (rlen) {
883f70ecafSeric 		log_warnx("warn: queue-proc: bogus data");
893f70ecafSeric 		fatalx("queue-proc: exiting");
903f70ecafSeric 	}
913f70ecafSeric 	imsg_free(&imsg);
923f70ecafSeric }
933f70ecafSeric 
943f70ecafSeric /*
953f70ecafSeric  * API
963f70ecafSeric  */
973f70ecafSeric 
983f70ecafSeric static int
9998f67d16Seric queue_proc_close(void)
10098f67d16Seric {
10198f67d16Seric 	int	r;
10298f67d16Seric 
103ef15259eSgilles 	imsg_compose(&ibuf, PROC_QUEUE_CLOSE, 0, 0, -1, NULL, 0);
10498f67d16Seric 
10598f67d16Seric 	queue_proc_call();
10698f67d16Seric 	queue_proc_read(&r, sizeof(r));
10798f67d16Seric 	queue_proc_end();
10898f67d16Seric 
10998f67d16Seric 	return (r);
11098f67d16Seric }
11198f67d16Seric 
11298f67d16Seric static int
1133f70ecafSeric queue_proc_message_create(uint32_t *msgid)
1143f70ecafSeric {
1153f70ecafSeric 	int	r;
1163f70ecafSeric 
1173f70ecafSeric 	imsg_compose(&ibuf, PROC_QUEUE_MESSAGE_CREATE, 0, 0, -1, NULL, 0);
1183f70ecafSeric 
1193f70ecafSeric 	queue_proc_call();
1203f70ecafSeric 	queue_proc_read(&r, sizeof(r));
1213f70ecafSeric 	if (r == 1)
1220d67db0cSeric 		queue_proc_read(msgid, sizeof(*msgid));
1233f70ecafSeric 	queue_proc_end();
1243f70ecafSeric 
1253f70ecafSeric 	return (r);
1263f70ecafSeric }
1273f70ecafSeric 
1283f70ecafSeric static int
1293f70ecafSeric queue_proc_message_commit(uint32_t msgid, const char *path)
1303f70ecafSeric {
1313f70ecafSeric 	int	r, fd;
1323f70ecafSeric 
1333f70ecafSeric 	fd = open(path, O_RDONLY);
1343f70ecafSeric 	if (fd == -1) {
1353f70ecafSeric 		log_warn("queue-proc: open: %s", path);
1363f70ecafSeric 		return (0);
1373f70ecafSeric 	}
1383f70ecafSeric 
1393f70ecafSeric 	imsg_compose(&ibuf, PROC_QUEUE_MESSAGE_COMMIT, 0, 0, fd, &msgid,
1403f70ecafSeric 	    sizeof(msgid));
1413f70ecafSeric 
1423f70ecafSeric 	queue_proc_call();
1433f70ecafSeric 	queue_proc_read(&r, sizeof(r));
1443f70ecafSeric 	queue_proc_end();
1453f70ecafSeric 
1463f70ecafSeric 	return (r);
1473f70ecafSeric }
1483f70ecafSeric 
1493f70ecafSeric static int
1503f70ecafSeric queue_proc_message_delete(uint32_t msgid)
1513f70ecafSeric {
1523f70ecafSeric 	int	r;
1533f70ecafSeric 
1543f70ecafSeric 	imsg_compose(&ibuf, PROC_QUEUE_MESSAGE_DELETE, 0, 0, -1, &msgid,
1553f70ecafSeric 	    sizeof(msgid));
1563f70ecafSeric 
1573f70ecafSeric 	queue_proc_call();
1583f70ecafSeric 	queue_proc_read(&r, sizeof(r));
1593f70ecafSeric 	queue_proc_end();
1603f70ecafSeric 
1613f70ecafSeric 	return (r);
1623f70ecafSeric }
1633f70ecafSeric 
1643f70ecafSeric static int
1653f70ecafSeric queue_proc_message_fd_r(uint32_t msgid)
1663f70ecafSeric {
1673f70ecafSeric 	imsg_compose(&ibuf, PROC_QUEUE_MESSAGE_FD_R, 0, 0, -1, &msgid,
1683f70ecafSeric 	    sizeof(msgid));
1693f70ecafSeric 
1703f70ecafSeric 	queue_proc_call();
1713f70ecafSeric 	queue_proc_end();
1723f70ecafSeric 
173510586acSclaudio 	return (imsg_get_fd(&imsg));
1743f70ecafSeric }
1753f70ecafSeric 
1763f70ecafSeric static int
1773f70ecafSeric queue_proc_envelope_create(uint32_t msgid, const char *buf, size_t len,
1783f70ecafSeric     uint64_t *evpid)
1793f70ecafSeric {
1803f70ecafSeric 	struct ibuf	*b;
1813f70ecafSeric 	int		 r;
1823f70ecafSeric 
1833f70ecafSeric 	msgid = evpid_to_msgid(*evpid);
1843f70ecafSeric 	b = imsg_create(&ibuf, PROC_QUEUE_ENVELOPE_CREATE, 0, 0,
1853f70ecafSeric 	    sizeof(msgid) + len);
1863f70ecafSeric 	if (imsg_add(b, &msgid, sizeof(msgid)) == -1 ||
1873f70ecafSeric 	    imsg_add(b, buf, len) == -1)
1883f70ecafSeric 		return (0);
1893f70ecafSeric 	imsg_close(&ibuf, b);
1903f70ecafSeric 
1913f70ecafSeric 	queue_proc_call();
1923f70ecafSeric 	queue_proc_read(&r, sizeof(r));
1933f70ecafSeric 	if (r == 1)
1943f70ecafSeric 		queue_proc_read(evpid, sizeof(*evpid));
1953f70ecafSeric 	queue_proc_end();
1963f70ecafSeric 
1973f70ecafSeric 	return (r);
1983f70ecafSeric }
1993f70ecafSeric 
2003f70ecafSeric static int
2013f70ecafSeric queue_proc_envelope_delete(uint64_t evpid)
2023f70ecafSeric {
2033f70ecafSeric 	int	r;
2043f70ecafSeric 
2053f70ecafSeric 	imsg_compose(&ibuf, PROC_QUEUE_ENVELOPE_DELETE, 0, 0, -1, &evpid,
2063f70ecafSeric 	    sizeof(evpid));
2073f70ecafSeric 
2083f70ecafSeric 	queue_proc_call();
2093f70ecafSeric 	queue_proc_read(&r, sizeof(r));
2103f70ecafSeric 	queue_proc_end();
2113f70ecafSeric 
2123f70ecafSeric 	return (r);
2133f70ecafSeric }
2143f70ecafSeric 
2153f70ecafSeric static int
2163f70ecafSeric queue_proc_envelope_update(uint64_t evpid, const char *buf, size_t len)
2173f70ecafSeric {
2183f70ecafSeric 	struct ibuf	*b;
2193f70ecafSeric 	int		 r;
2203f70ecafSeric 
2213f70ecafSeric 	b = imsg_create(&ibuf, PROC_QUEUE_ENVELOPE_UPDATE, 0, 0,
2223f70ecafSeric 	    len + sizeof(evpid));
2233f70ecafSeric 	if (imsg_add(b, &evpid, sizeof(evpid)) == -1 ||
2243f70ecafSeric 	    imsg_add(b, buf, len) == -1)
2253f70ecafSeric 		return (0);
2263f70ecafSeric 	imsg_close(&ibuf, b);
2273f70ecafSeric 
2283f70ecafSeric 	queue_proc_call();
2293f70ecafSeric 	queue_proc_read(&r, sizeof(r));
2303f70ecafSeric 	queue_proc_end();
2313f70ecafSeric 
2323f70ecafSeric 	return (r);
2333f70ecafSeric }
2343f70ecafSeric 
2353f70ecafSeric static int
2363f70ecafSeric queue_proc_envelope_load(uint64_t evpid, char *buf, size_t len)
2373f70ecafSeric {
2383f70ecafSeric 	int	r;
2393f70ecafSeric 
2403f70ecafSeric 	imsg_compose(&ibuf, PROC_QUEUE_ENVELOPE_LOAD, 0, 0, -1, &evpid,
2413f70ecafSeric 	    sizeof(evpid));
2423f70ecafSeric 
2433f70ecafSeric 	queue_proc_call();
2443f70ecafSeric 
2453f70ecafSeric 	if (rlen > len) {
2463f70ecafSeric 		log_warnx("warn: queue-proc: buf too small");
2473f70ecafSeric 		fatalx("queue-proc: exiting");
2483f70ecafSeric 	}
2493f70ecafSeric 
2503f70ecafSeric 	r = rlen;
25198f67d16Seric 	queue_proc_read(buf, rlen);
2523f70ecafSeric 	queue_proc_end();
2533f70ecafSeric 
2543f70ecafSeric 	return (r);
2553f70ecafSeric }
2563f70ecafSeric 
2573f70ecafSeric static int
2583f70ecafSeric queue_proc_envelope_walk(uint64_t *evpid, char *buf, size_t len)
2593f70ecafSeric {
2603f70ecafSeric 	int	r;
2613f70ecafSeric 
2623f70ecafSeric 	imsg_compose(&ibuf, PROC_QUEUE_ENVELOPE_WALK, 0, 0, -1, NULL, 0);
2633f70ecafSeric 
2643f70ecafSeric 	queue_proc_call();
2653f70ecafSeric 	queue_proc_read(&r, sizeof(r));
2663f70ecafSeric 
2673f70ecafSeric 	if (r > 0) {
2683f70ecafSeric 		queue_proc_read(evpid, sizeof(*evpid));
2693f70ecafSeric 		if (rlen > len) {
2703f70ecafSeric 			log_warnx("warn: queue-proc: buf too small");
2713f70ecafSeric 			fatalx("queue-proc: exiting");
2723f70ecafSeric 		}
2733f70ecafSeric 		if (r != (int)rlen) {
2743f70ecafSeric 			log_warnx("warn: queue-proc: len mismatch");
2753f70ecafSeric 			fatalx("queue-proc: exiting");
2763f70ecafSeric 		}
27798f67d16Seric 		queue_proc_read(buf, rlen);
2783f70ecafSeric 	}
2793f70ecafSeric 	queue_proc_end();
2803f70ecafSeric 
2813f70ecafSeric 	return (r);
2823f70ecafSeric }
2833f70ecafSeric 
2843f70ecafSeric static int
28598f67d16Seric queue_proc_init(struct passwd *pw, int server, const char *conf)
2863f70ecafSeric {
2873f70ecafSeric 	uint32_t	version;
28898f67d16Seric 	int		fd;
2893f70ecafSeric 
2908380d000Sop 	fd = fork_proc_backend("queue", conf, "queue-proc", 0);
29198f67d16Seric 	if (fd == -1)
29298f67d16Seric 		fatalx("queue-proc: exiting");
2933f70ecafSeric 
294*bf921b2aSclaudio 	if (imsgbuf_init(&ibuf, fd) == -1)
295*bf921b2aSclaudio 		fatal("queue-proc: exiting");
296*bf921b2aSclaudio 	imsgbuf_allow_fdpass(&ibuf);
2973f70ecafSeric 
2983f70ecafSeric 	version = PROC_QUEUE_API_VERSION;
2993f70ecafSeric 	imsg_compose(&ibuf, PROC_QUEUE_INIT, 0, 0, -1,
3003f70ecafSeric 	    &version, sizeof(version));
3013f70ecafSeric 
30298f67d16Seric 	queue_api_on_close(queue_proc_close);
3033f70ecafSeric 	queue_api_on_message_create(queue_proc_message_create);
3043f70ecafSeric 	queue_api_on_message_commit(queue_proc_message_commit);
3053f70ecafSeric 	queue_api_on_message_delete(queue_proc_message_delete);
3063f70ecafSeric 	queue_api_on_message_fd_r(queue_proc_message_fd_r);
3073f70ecafSeric 	queue_api_on_envelope_create(queue_proc_envelope_create);
3083f70ecafSeric 	queue_api_on_envelope_delete(queue_proc_envelope_delete);
3093f70ecafSeric 	queue_api_on_envelope_update(queue_proc_envelope_update);
3103f70ecafSeric 	queue_api_on_envelope_load(queue_proc_envelope_load);
3113f70ecafSeric 	queue_api_on_envelope_walk(queue_proc_envelope_walk);
3123f70ecafSeric 
3133f70ecafSeric 	queue_proc_call();
3143f70ecafSeric 	queue_proc_end();
3153f70ecafSeric 
3163f70ecafSeric 	return (1);
3173f70ecafSeric }
3183f70ecafSeric 
3193f70ecafSeric struct queue_backend	queue_backend_proc = {
3203f70ecafSeric 	queue_proc_init,
3213f70ecafSeric };
322