xref: /openbsd-src/usr.sbin/smtpd/queue_ram.c (revision d3140113bef2b86d3af61dd20c05a8630ff966c2)
1*d3140113Seric /*	$OpenBSD: queue_ram.c,v 1.11 2021/06/14 17:58:16 eric Exp $	*/
265c4fdfbSgilles 
365c4fdfbSgilles /*
465c4fdfbSgilles  * Copyright (c) 2012 Eric Faurot <eric@openbsd.org>
565c4fdfbSgilles  *
665c4fdfbSgilles  * Permission to use, copy, modify, and distribute this software for any
765c4fdfbSgilles  * purpose with or without fee is hereby granted, provided that the above
865c4fdfbSgilles  * copyright notice and this permission notice appear in all copies.
965c4fdfbSgilles  *
1065c4fdfbSgilles  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1165c4fdfbSgilles  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1265c4fdfbSgilles  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1365c4fdfbSgilles  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1465c4fdfbSgilles  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1565c4fdfbSgilles  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1665c4fdfbSgilles  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1765c4fdfbSgilles  */
1865c4fdfbSgilles 
1965c4fdfbSgilles #include <sys/stat.h>
2065c4fdfbSgilles 
2165c4fdfbSgilles #include <stdlib.h>
2265c4fdfbSgilles #include <string.h>
2365c4fdfbSgilles #include <unistd.h>
2465c4fdfbSgilles 
2565c4fdfbSgilles #include "smtpd.h"
2665c4fdfbSgilles #include "log.h"
2765c4fdfbSgilles 
2865c4fdfbSgilles struct qr_envelope {
2965c4fdfbSgilles 	char		*buf;
3065c4fdfbSgilles 	size_t		 len;
3165c4fdfbSgilles };
3265c4fdfbSgilles 
3365c4fdfbSgilles struct qr_message {
3465c4fdfbSgilles 	char		*buf;
3565c4fdfbSgilles 	size_t		 len;
3665c4fdfbSgilles 	struct tree	 envelopes;
3765c4fdfbSgilles };
3865c4fdfbSgilles 
3965c4fdfbSgilles static struct tree messages;
4065c4fdfbSgilles 
413f70ecafSeric static struct qr_message *
get_message(uint32_t msgid)423f70ecafSeric get_message(uint32_t msgid)
4365c4fdfbSgilles {
443f70ecafSeric 	struct qr_message	*msg;
453f70ecafSeric 
463f70ecafSeric         msg = tree_get(&messages, msgid);
473f70ecafSeric         if (msg == NULL)
483f70ecafSeric                 log_warn("warn: queue-ram: message not found");
493f70ecafSeric 
503f70ecafSeric 	return (msg);
513f70ecafSeric }
523f70ecafSeric 
533f70ecafSeric static int
queue_ram_message_create(uint32_t * msgid)543f70ecafSeric queue_ram_message_create(uint32_t *msgid)
553f70ecafSeric {
563f70ecafSeric 	struct qr_message	*msg;
573f70ecafSeric 
583f70ecafSeric 	msg = calloc(1, sizeof(*msg));
593f70ecafSeric 	if (msg == NULL) {
603f70ecafSeric 		log_warn("warn: queue-ram: calloc");
613f70ecafSeric 		return (0);
623f70ecafSeric 	}
633f70ecafSeric 	tree_init(&msg->envelopes);
643f70ecafSeric 
653f70ecafSeric 	do {
663f70ecafSeric 		*msgid = queue_generate_msgid();
673f70ecafSeric 	} while (tree_check(&messages, *msgid));
683f70ecafSeric 
693f70ecafSeric 	tree_xset(&messages, *msgid, msg);
7065c4fdfbSgilles 
7165c4fdfbSgilles 	return (1);
7265c4fdfbSgilles }
7365c4fdfbSgilles 
7465c4fdfbSgilles static int
queue_ram_message_commit(uint32_t msgid,const char * path)753f70ecafSeric queue_ram_message_commit(uint32_t msgid, const char *path)
7665c4fdfbSgilles {
7765c4fdfbSgilles 	struct qr_message	*msg;
7865c4fdfbSgilles 	struct stat		 sb;
7965c4fdfbSgilles 	size_t			 n;
803f70ecafSeric 	FILE			*f;
813f70ecafSeric 	int			 ret;
8265c4fdfbSgilles 
833f70ecafSeric 	if ((msg = tree_get(&messages, msgid)) == NULL) {
843f70ecafSeric 		log_warnx("warn: queue-ram: msgid not found");
853f70ecafSeric 		return (0);
863f70ecafSeric 	}
8765c4fdfbSgilles 
883f70ecafSeric 	f = fopen(path, "rb");
893f70ecafSeric 	if (f == NULL) {
903f70ecafSeric 		log_warn("warn: queue-ram: fopen: %s", path);
913f70ecafSeric 		return (0);
923f70ecafSeric 	}
933f70ecafSeric 	if (fstat(fileno(f), &sb) == -1) {
943f70ecafSeric 		log_warn("warn: queue-ram: fstat");
953f70ecafSeric 		fclose(f);
963f70ecafSeric 		return (0);
973f70ecafSeric 	}
983f70ecafSeric 
993f70ecafSeric 	msg->len = sb.st_size;
1003f70ecafSeric 	msg->buf = malloc(msg->len);
1013f70ecafSeric 	if (msg->buf == NULL) {
1023f70ecafSeric 		log_warn("warn: queue-ram: malloc");
1033f70ecafSeric 		fclose(f);
1043f70ecafSeric 		return (0);
1053f70ecafSeric 	}
1063f70ecafSeric 
1073f70ecafSeric 	ret = 0;
1083f70ecafSeric 	n = fread(msg->buf, 1, msg->len, f);
1093f70ecafSeric 	if (ferror(f))
1103f70ecafSeric 		log_warn("warn: queue-ram: fread");
1113f70ecafSeric 	else if ((off_t)n != sb.st_size)
1123f70ecafSeric 		log_warnx("warn: queue-ram: bad read");
1133f70ecafSeric 	else {
1143f70ecafSeric 		ret = 1;
1153f70ecafSeric 		stat_increment("queue.ram.message.size", msg->len);
1163f70ecafSeric 	}
1173f70ecafSeric 	fclose(f);
1183f70ecafSeric 
1193f70ecafSeric 	return (ret);
1203f70ecafSeric }
1213f70ecafSeric 
1223f70ecafSeric static int
queue_ram_message_delete(uint32_t msgid)1233f70ecafSeric queue_ram_message_delete(uint32_t msgid)
1243f70ecafSeric {
1253f70ecafSeric 	struct qr_message	*msg;
1263f70ecafSeric 	struct qr_envelope	*evp;
1273f70ecafSeric 	uint64_t		 evpid;
1283f70ecafSeric 
1293f70ecafSeric 	if ((msg = tree_pop(&messages, msgid)) == NULL) {
1303f70ecafSeric 		log_warnx("warn: queue-ram: not found");
13165c4fdfbSgilles 		return (0);
13265c4fdfbSgilles 	}
13365c4fdfbSgilles 	while (tree_poproot(&messages, &evpid, (void**)&evp)) {
13465c4fdfbSgilles 		stat_decrement("queue.ram.envelope.size", evp->len);
13565c4fdfbSgilles 		free(evp->buf);
13665c4fdfbSgilles 		free(evp);
13765c4fdfbSgilles 	}
13865c4fdfbSgilles 	stat_decrement("queue.ram.message.size", msg->len);
13965c4fdfbSgilles 	free(msg->buf);
14065c4fdfbSgilles 	free(msg);
14165c4fdfbSgilles 	return (0);
14265c4fdfbSgilles }
14365c4fdfbSgilles 
1443f70ecafSeric static int
queue_ram_message_fd_r(uint32_t msgid)1453f70ecafSeric queue_ram_message_fd_r(uint32_t msgid)
1463f70ecafSeric {
1473f70ecafSeric 	struct qr_message	*msg;
1483f70ecafSeric 	size_t			 n;
1493f70ecafSeric 	FILE			*f;
1503f70ecafSeric 	int			 fd, fd2;
15165c4fdfbSgilles 
1523f70ecafSeric 	if ((msg = tree_get(&messages, msgid)) == NULL) {
1533f70ecafSeric 		log_warnx("warn: queue-ram: not found");
15465c4fdfbSgilles 		return (-1);
15565c4fdfbSgilles 	}
1563f70ecafSeric 
15765c4fdfbSgilles 	fd = mktmpfile();
15865c4fdfbSgilles 	if (fd == -1) {
1593f70ecafSeric 		log_warn("warn: queue-ram: mktmpfile");
16065c4fdfbSgilles 		return (-1);
16165c4fdfbSgilles 	}
1623f70ecafSeric 
16365c4fdfbSgilles 	fd2 = dup(fd);
16465c4fdfbSgilles 	if (fd2 == -1) {
1653f70ecafSeric 		log_warn("warn: queue-ram: dup");
16665c4fdfbSgilles 		close(fd);
16765c4fdfbSgilles 		return (-1);
16865c4fdfbSgilles 	}
16965c4fdfbSgilles 	f = fdopen(fd2, "w");
17065c4fdfbSgilles 	if (f == NULL) {
1713f70ecafSeric 		log_warn("warn: queue-ram: fdopen");
17265c4fdfbSgilles 		close(fd);
17365c4fdfbSgilles 		close(fd2);
17465c4fdfbSgilles 		return (-1);
17565c4fdfbSgilles 	}
17665c4fdfbSgilles 	n = fwrite(msg->buf, 1, msg->len, f);
17765c4fdfbSgilles 	if (n != msg->len) {
1783f70ecafSeric 		log_warn("warn: queue-ram: write");
17965c4fdfbSgilles 		close(fd);
18065c4fdfbSgilles 		fclose(f);
18165c4fdfbSgilles 		return (-1);
18265c4fdfbSgilles 	}
18365c4fdfbSgilles 	fclose(f);
18465c4fdfbSgilles 	lseek(fd, 0, SEEK_SET);
18565c4fdfbSgilles 	return (fd);
18665c4fdfbSgilles }
18765c4fdfbSgilles 
18865c4fdfbSgilles static int
queue_ram_envelope_create(uint32_t msgid,const char * buf,size_t len,uint64_t * evpid)1893f70ecafSeric queue_ram_envelope_create(uint32_t msgid, const char *buf, size_t len,
1903f70ecafSeric     uint64_t *evpid)
19165c4fdfbSgilles {
19265c4fdfbSgilles 	struct qr_envelope	*evp;
19365c4fdfbSgilles 	struct qr_message	*msg;
19465c4fdfbSgilles 
1953f70ecafSeric 	if ((msg = get_message(msgid)) == NULL)
19665c4fdfbSgilles 		return (0);
19765c4fdfbSgilles 
19865c4fdfbSgilles 	do {
19965c4fdfbSgilles 		*evpid = queue_generate_evpid(msgid);
20065c4fdfbSgilles 	} while (tree_check(&msg->envelopes, *evpid));
20165c4fdfbSgilles 	evp = calloc(1, sizeof *evp);
20265c4fdfbSgilles 	if (evp == NULL) {
2033f70ecafSeric 		log_warn("warn: queue-ram: calloc");
20465c4fdfbSgilles 		return (0);
20565c4fdfbSgilles 	}
20665c4fdfbSgilles 	evp->len = len;
20765c4fdfbSgilles 	evp->buf = malloc(len);
20865c4fdfbSgilles 	if (evp->buf == NULL) {
2093f70ecafSeric 		log_warn("warn: queue-ram: malloc");
2101c6ac251Seric 		free(evp);
21165c4fdfbSgilles 		return (0);
21265c4fdfbSgilles 	}
21365c4fdfbSgilles 	memmove(evp->buf, buf, len);
21465c4fdfbSgilles 	tree_xset(&msg->envelopes, *evpid, evp);
21565c4fdfbSgilles 	stat_increment("queue.ram.envelope.size", len);
21665c4fdfbSgilles 	return (1);
2173f70ecafSeric }
21865c4fdfbSgilles 
2193f70ecafSeric static int
queue_ram_envelope_delete(uint64_t evpid)2203f70ecafSeric queue_ram_envelope_delete(uint64_t evpid)
2213f70ecafSeric {
2223f70ecafSeric 	struct qr_envelope	*evp;
2233f70ecafSeric 	struct qr_message	*msg;
2243f70ecafSeric 
2253f70ecafSeric 	if ((msg = get_message(evpid_to_msgid(evpid))) == NULL)
2263f70ecafSeric 		return (0);
2273f70ecafSeric 
2283f70ecafSeric 	if ((evp = tree_pop(&msg->envelopes, evpid)) == NULL) {
2293f70ecafSeric 		log_warnx("warn: queue-ram: not found");
23065c4fdfbSgilles 		return (0);
23165c4fdfbSgilles 	}
23265c4fdfbSgilles 	stat_decrement("queue.ram.envelope.size", evp->len);
23365c4fdfbSgilles 	free(evp->buf);
23465c4fdfbSgilles 	free(evp);
23565c4fdfbSgilles 	if (tree_empty(&msg->envelopes)) {
2363f70ecafSeric 		tree_xpop(&messages, evpid_to_msgid(evpid));
23765c4fdfbSgilles 		stat_decrement("queue.ram.message.size", msg->len);
23865c4fdfbSgilles 		free(msg->buf);
23965c4fdfbSgilles 		free(msg);
24065c4fdfbSgilles 	}
24165c4fdfbSgilles 	return (1);
24265c4fdfbSgilles }
24365c4fdfbSgilles 
2443f70ecafSeric static int
queue_ram_envelope_update(uint64_t evpid,const char * buf,size_t len)2453f70ecafSeric queue_ram_envelope_update(uint64_t evpid, const char *buf, size_t len)
2463f70ecafSeric {
2473f70ecafSeric 	struct qr_envelope	*evp;
2483f70ecafSeric 	struct qr_message	*msg;
2493f70ecafSeric 	void			*tmp;
2503f70ecafSeric 
2513f70ecafSeric 	if ((msg = get_message(evpid_to_msgid(evpid))) == NULL)
2523f70ecafSeric 		return (0);
2533f70ecafSeric 
2543f70ecafSeric 	if ((evp = tree_get(&msg->envelopes, evpid)) == NULL) {
2553f70ecafSeric 		log_warn("warn: queue-ram: not found");
25665c4fdfbSgilles 		return (0);
25765c4fdfbSgilles 	}
25865c4fdfbSgilles 	tmp = malloc(len);
25965c4fdfbSgilles 	if (tmp == NULL) {
2603f70ecafSeric 		log_warn("warn: queue-ram: malloc");
26165c4fdfbSgilles 		return (0);
26265c4fdfbSgilles 	}
26365c4fdfbSgilles 	memmove(tmp, buf, len);
26465c4fdfbSgilles 	free(evp->buf);
26565c4fdfbSgilles 	evp->len = len;
26665c4fdfbSgilles 	evp->buf = tmp;
26765c4fdfbSgilles 	stat_decrement("queue.ram.envelope.size", evp->len);
26865c4fdfbSgilles 	stat_increment("queue.ram.envelope.size", len);
26965c4fdfbSgilles 	return (1);
27065c4fdfbSgilles }
27165c4fdfbSgilles 
2723f70ecafSeric static int
queue_ram_envelope_load(uint64_t evpid,char * buf,size_t len)2733f70ecafSeric queue_ram_envelope_load(uint64_t evpid, char *buf, size_t len)
2743f70ecafSeric {
2753f70ecafSeric 	struct qr_envelope	*evp;
2763f70ecafSeric 	struct qr_message	*msg;
2773f70ecafSeric 
2783f70ecafSeric 	if ((msg = get_message(evpid_to_msgid(evpid))) == NULL)
2793f70ecafSeric 		return (0);
2803f70ecafSeric 
2813f70ecafSeric 	if ((evp = tree_get(&msg->envelopes, evpid)) == NULL) {
2823f70ecafSeric 		log_warn("warn: queue-ram: not found");
28365c4fdfbSgilles 		return (0);
28465c4fdfbSgilles 	}
2853f70ecafSeric 	if (len < evp->len) {
2863f70ecafSeric 		log_warnx("warn: queue-ram: buffer too small");
2873f70ecafSeric 		return (0);
2883f70ecafSeric 	}
2893f70ecafSeric 	memmove(buf, evp->buf, evp->len);
2903f70ecafSeric 	return (evp->len);
2913f70ecafSeric }
2923f70ecafSeric 
2933f70ecafSeric static int
queue_ram_envelope_walk(uint64_t * evpid,char * buf,size_t len)2943f70ecafSeric queue_ram_envelope_walk(uint64_t *evpid, char *buf, size_t len)
2953f70ecafSeric {
2963f70ecafSeric 	return (-1);
2973f70ecafSeric }
2983f70ecafSeric 
2993f70ecafSeric static int
queue_ram_init(struct passwd * pw,int server,const char * conf)30098f67d16Seric queue_ram_init(struct passwd *pw, int server, const char * conf)
3013f70ecafSeric {
3023f70ecafSeric 	tree_init(&messages);
3033f70ecafSeric 
3043f70ecafSeric 	queue_api_on_message_create(queue_ram_message_create);
3053f70ecafSeric 	queue_api_on_message_commit(queue_ram_message_commit);
3063f70ecafSeric 	queue_api_on_message_delete(queue_ram_message_delete);
3073f70ecafSeric 	queue_api_on_message_fd_r(queue_ram_message_fd_r);
3083f70ecafSeric 	queue_api_on_envelope_create(queue_ram_envelope_create);
3093f70ecafSeric 	queue_api_on_envelope_delete(queue_ram_envelope_delete);
3103f70ecafSeric 	queue_api_on_envelope_update(queue_ram_envelope_update);
3113f70ecafSeric 	queue_api_on_envelope_load(queue_ram_envelope_load);
3123f70ecafSeric 	queue_api_on_envelope_walk(queue_ram_envelope_walk);
3133f70ecafSeric 
3143f70ecafSeric 	return (1);
3153f70ecafSeric }
3163f70ecafSeric 
3173f70ecafSeric struct queue_backend	queue_backend_ram = {
3183f70ecafSeric 	queue_ram_init,
3193f70ecafSeric };
320