xref: /openbsd-src/usr.sbin/smtpd/mproc.c (revision bf921b2a265b968a018032bb165729419e711549)
1*bf921b2aSclaudio /*	$OpenBSD: mproc.c,v 1.47 2024/11/21 13:42:22 claudio Exp $	*/
265c4fdfbSgilles 
365c4fdfbSgilles /*
465c4fdfbSgilles  * Copyright (c) 2012 Eric Faurot <eric@faurot.net>
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 <errno.h>
2065c4fdfbSgilles #include <stdlib.h>
2165c4fdfbSgilles #include <string.h>
2265c4fdfbSgilles #include <unistd.h>
2365c4fdfbSgilles 
2465c4fdfbSgilles #include "smtpd.h"
2565c4fdfbSgilles #include "log.h"
2665c4fdfbSgilles 
2765c4fdfbSgilles static void mproc_dispatch(int, short, void *);
2865c4fdfbSgilles 
2965c4fdfbSgilles int
30d6f2ac01Seric mproc_fork(struct mproc *p, const char *path, char *argv[])
3165c4fdfbSgilles {
3265c4fdfbSgilles 	int sp[2];
3365c4fdfbSgilles 
34df69c215Sderaadt 	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, sp) == -1)
3565c4fdfbSgilles 		return (-1);
3665c4fdfbSgilles 
37907c4b99Skrw 	io_set_nonblocking(sp[0]);
38907c4b99Skrw 	io_set_nonblocking(sp[1]);
3965c4fdfbSgilles 
4065c4fdfbSgilles 	if ((p->pid = fork()) == -1)
4165c4fdfbSgilles 		goto err;
4265c4fdfbSgilles 
4365c4fdfbSgilles 	if (p->pid == 0) {
4465c4fdfbSgilles 		/* child process */
4565c4fdfbSgilles 		dup2(sp[0], STDIN_FILENO);
46df69c215Sderaadt 		if (closefrom(STDERR_FILENO + 1) == -1)
4765c4fdfbSgilles 			exit(1);
4865c4fdfbSgilles 
49d6f2ac01Seric 		execv(path, argv);
50ff01b044Seric 		fatal("execv: %s", path);
5165c4fdfbSgilles 	}
5265c4fdfbSgilles 
5365c4fdfbSgilles 	/* parent process */
5465c4fdfbSgilles 	close(sp[0]);
5565c4fdfbSgilles 	mproc_init(p, sp[1]);
5665c4fdfbSgilles 	return (0);
5765c4fdfbSgilles 
5865c4fdfbSgilles err:
59d6f2ac01Seric 	log_warn("warn: Failed to start process %s, instance of %s", argv[0], path);
6065c4fdfbSgilles 	close(sp[0]);
6165c4fdfbSgilles 	close(sp[1]);
6265c4fdfbSgilles 	return (-1);
6365c4fdfbSgilles }
6465c4fdfbSgilles 
6565c4fdfbSgilles void
6665c4fdfbSgilles mproc_init(struct mproc *p, int fd)
6765c4fdfbSgilles {
68*bf921b2aSclaudio 	if (imsgbuf_init(&p->imsgbuf, fd) == -1)
69*bf921b2aSclaudio 		fatal("mproc_init: imsgbuf_init");
70*bf921b2aSclaudio 	if (p->proc != PROC_CLIENT)
71*bf921b2aSclaudio 		imsgbuf_allow_fdpass(&p->imsgbuf);
7265c4fdfbSgilles }
7365c4fdfbSgilles 
7465c4fdfbSgilles void
7565c4fdfbSgilles mproc_clear(struct mproc *p)
7665c4fdfbSgilles {
7743962b9cSeric 	log_debug("debug: clearing p=%s, fd=%d, pid=%d", p->name, p->imsgbuf.fd, p->pid);
7843962b9cSeric 
79ef75f1bdSmartijn 	if (p->events)
8065c4fdfbSgilles 		event_del(&p->ev);
8165c4fdfbSgilles 	close(p->imsgbuf.fd);
82dd7efffeSclaudio 	imsgbuf_clear(&p->imsgbuf);
8365c4fdfbSgilles }
8465c4fdfbSgilles 
8565c4fdfbSgilles void
8665c4fdfbSgilles mproc_enable(struct mproc *p)
8765c4fdfbSgilles {
8865c4fdfbSgilles 	if (p->enable == 0) {
89299c4efeSeric 		log_trace(TRACE_MPROC, "mproc: %s -> %s: enabled",
90299c4efeSeric 		    proc_name(smtpd_process),
9165c4fdfbSgilles 		    proc_name(p->proc));
9265c4fdfbSgilles 		p->enable = 1;
9365c4fdfbSgilles 	}
9465c4fdfbSgilles 	mproc_event_add(p);
9565c4fdfbSgilles }
9665c4fdfbSgilles 
9765c4fdfbSgilles void
9865c4fdfbSgilles mproc_disable(struct mproc *p)
9965c4fdfbSgilles {
10065c4fdfbSgilles 	if (p->enable == 1) {
101299c4efeSeric 		log_trace(TRACE_MPROC, "mproc: %s -> %s: disabled",
102299c4efeSeric 		    proc_name(smtpd_process),
10365c4fdfbSgilles 		    proc_name(p->proc));
10465c4fdfbSgilles 		p->enable = 0;
10565c4fdfbSgilles 	}
10665c4fdfbSgilles 	mproc_event_add(p);
10765c4fdfbSgilles }
10865c4fdfbSgilles 
109c4df3bf2Sreyk void
11065c4fdfbSgilles mproc_event_add(struct mproc *p)
11165c4fdfbSgilles {
11265c4fdfbSgilles 	short	events;
11365c4fdfbSgilles 
11465c4fdfbSgilles 	if (p->enable)
11565c4fdfbSgilles 		events = EV_READ;
11665c4fdfbSgilles 	else
11765c4fdfbSgilles 		events = 0;
11865c4fdfbSgilles 
11931be28caSclaudio 	if (imsgbuf_queuelen(&p->imsgbuf) > 0)
12065c4fdfbSgilles 		events |= EV_WRITE;
12165c4fdfbSgilles 
12265c4fdfbSgilles 	if (p->events)
12365c4fdfbSgilles 		event_del(&p->ev);
12465c4fdfbSgilles 
12565c4fdfbSgilles 	p->events = events;
12665c4fdfbSgilles 	if (events) {
12765c4fdfbSgilles 		event_set(&p->ev, p->imsgbuf.fd, events, mproc_dispatch, p);
12865c4fdfbSgilles 		event_add(&p->ev, NULL);
12965c4fdfbSgilles 	}
13065c4fdfbSgilles }
13165c4fdfbSgilles 
13265c4fdfbSgilles static void
13365c4fdfbSgilles mproc_dispatch(int fd, short event, void *arg)
13465c4fdfbSgilles {
13565c4fdfbSgilles 	struct mproc	*p = arg;
13665c4fdfbSgilles 	struct imsg	 imsg;
13765c4fdfbSgilles 	ssize_t		 n;
13865c4fdfbSgilles 
13965c4fdfbSgilles 	p->events = 0;
14065c4fdfbSgilles 
14165c4fdfbSgilles 	if (event & EV_READ) {
14265c4fdfbSgilles 
143dd7efffeSclaudio 		n = imsgbuf_read(&p->imsgbuf);
144cc03c9a7Sgilles 
1451a473d40Smillert 		switch (n) {
1461a473d40Smillert 		case -1:
147dd7efffeSclaudio 			log_warn("warn: %s -> %s: imsgbuf_read",
148299c4efeSeric 			    proc_name(smtpd_process),  p->name);
149299c4efeSeric 			fatal("exiting");
1501a473d40Smillert 			/* NOTREACHED */
1511a473d40Smillert 		case 0:
15265c4fdfbSgilles 			/* this pipe is dead, so remove the event handler */
15343962b9cSeric 			log_debug("debug: %s -> %s: pipe closed",
154299c4efeSeric 			    proc_name(smtpd_process),  p->name);
15565c4fdfbSgilles 			p->handler(p, NULL);
15665c4fdfbSgilles 			return;
1571a473d40Smillert 		default:
1581a473d40Smillert 			break;
1591a473d40Smillert 		}
16065c4fdfbSgilles 	}
16165c4fdfbSgilles 
16265c4fdfbSgilles 	if (event & EV_WRITE) {
163dd7efffeSclaudio 		if (imsgbuf_write(&p->imsgbuf) == -1) {
1645db1b16bSeric 			/* this pipe is dead, so remove the event handler */
16543962b9cSeric 			log_debug("debug: %s -> %s: pipe closed",
1665db1b16bSeric 			    proc_name(smtpd_process),  p->name);
1675db1b16bSeric 			p->handler(p, NULL);
1685db1b16bSeric 			return;
16965c4fdfbSgilles 		}
1702f366c99Seric 	}
17165c4fdfbSgilles 
17265c4fdfbSgilles 	for (;;) {
1731c6ac251Seric 		if ((n = imsg_get(&p->imsgbuf, &imsg)) == -1) {
1748e9397b5Sgilles 
1758e9397b5Sgilles 			if (smtpd_process == PROC_CONTROL &&
1768e9397b5Sgilles 			    p->proc == PROC_CLIENT) {
1778e9397b5Sgilles 				log_warnx("warn: client sent invalid imsg "
1788e9397b5Sgilles 				    "over control socket");
1798e9397b5Sgilles 				p->handler(p, NULL);
1808e9397b5Sgilles 				return;
1818e9397b5Sgilles 			}
1821c6ac251Seric 			log_warn("fatal: %s: error in imsg_get for %s",
1831c6ac251Seric 			    proc_name(smtpd_process),  p->name);
1841c6ac251Seric 			fatalx(NULL);
1851c6ac251Seric 		}
18665c4fdfbSgilles 		if (n == 0)
18765c4fdfbSgilles 			break;
18865c4fdfbSgilles 
18965c4fdfbSgilles 		p->handler(p, &imsg);
19065c4fdfbSgilles 
19165c4fdfbSgilles 		imsg_free(&imsg);
19265c4fdfbSgilles 	}
19365c4fdfbSgilles 
19465c4fdfbSgilles 	mproc_event_add(p);
19565c4fdfbSgilles }
19665c4fdfbSgilles 
19765c4fdfbSgilles void
19865c4fdfbSgilles m_forward(struct mproc *p, struct imsg *imsg)
19965c4fdfbSgilles {
20065c4fdfbSgilles 	imsg_compose(&p->imsgbuf, imsg->hdr.type, imsg->hdr.peerid,
201510586acSclaudio 	    imsg->hdr.pid, imsg_get_fd(imsg), imsg->data,
20265c4fdfbSgilles 	    imsg->hdr.len - sizeof(imsg->hdr));
20365c4fdfbSgilles 
204a6d7bf9fSgilles 	if (imsg->hdr.type != IMSG_STAT_DECREMENT &&
205a6d7bf9fSgilles 	    imsg->hdr.type != IMSG_STAT_INCREMENT)
206299c4efeSeric 		log_trace(TRACE_MPROC, "mproc: %s -> %s : %zu %s (forward)",
207299c4efeSeric 		    proc_name(smtpd_process),
208299c4efeSeric 		    proc_name(p->proc),
209299c4efeSeric 		    imsg->hdr.len - sizeof(imsg->hdr),
210299c4efeSeric 		    imsg_to_str(imsg->hdr.type));
211299c4efeSeric 
21265c4fdfbSgilles 	mproc_event_add(p);
21365c4fdfbSgilles }
21465c4fdfbSgilles 
21565c4fdfbSgilles void
21665c4fdfbSgilles m_compose(struct mproc *p, uint32_t type, uint32_t peerid, pid_t pid, int fd,
21765c4fdfbSgilles     void *data, size_t len)
21865c4fdfbSgilles {
21965c4fdfbSgilles 	imsg_compose(&p->imsgbuf, type, peerid, pid, fd, data, len);
22065c4fdfbSgilles 
221a6d7bf9fSgilles 	if (type != IMSG_STAT_DECREMENT &&
222a6d7bf9fSgilles 	    type != IMSG_STAT_INCREMENT)
223299c4efeSeric 		log_trace(TRACE_MPROC, "mproc: %s -> %s : %zu %s",
224299c4efeSeric 		    proc_name(smtpd_process),
225299c4efeSeric 		    proc_name(p->proc),
226299c4efeSeric 		    len,
227299c4efeSeric 		    imsg_to_str(type));
228299c4efeSeric 
22965c4fdfbSgilles 	mproc_event_add(p);
23065c4fdfbSgilles }
23165c4fdfbSgilles 
23265c4fdfbSgilles void
23365c4fdfbSgilles m_composev(struct mproc *p, uint32_t type, uint32_t peerid, pid_t pid,
23465c4fdfbSgilles     int fd, const struct iovec *iov, int n)
23565c4fdfbSgilles {
236299c4efeSeric 	size_t	len;
23765c4fdfbSgilles 	int	i;
23865c4fdfbSgilles 
23965c4fdfbSgilles 	imsg_composev(&p->imsgbuf, type, peerid, pid, fd, iov, n);
24065c4fdfbSgilles 
241299c4efeSeric 	len = 0;
24265c4fdfbSgilles 	for (i = 0; i < n; i++)
243299c4efeSeric 		len += iov[i].iov_len;
244299c4efeSeric 
245a6d7bf9fSgilles 	if (type != IMSG_STAT_DECREMENT &&
246a6d7bf9fSgilles 	    type != IMSG_STAT_INCREMENT)
247299c4efeSeric 		log_trace(TRACE_MPROC, "mproc: %s -> %s : %zu %s",
248299c4efeSeric 		    proc_name(smtpd_process),
249299c4efeSeric 		    proc_name(p->proc),
250299c4efeSeric 		    len,
251299c4efeSeric 		    imsg_to_str(type));
252299c4efeSeric 
25365c4fdfbSgilles 	mproc_event_add(p);
25465c4fdfbSgilles }
25565c4fdfbSgilles 
25665c4fdfbSgilles void
257299c4efeSeric m_create(struct mproc *p, uint32_t type, uint32_t peerid, pid_t pid, int fd)
25865c4fdfbSgilles {
259299c4efeSeric 	p->m_pos = 0;
260299c4efeSeric 	p->m_type = type;
261299c4efeSeric 	p->m_peerid = peerid;
262299c4efeSeric 	p->m_pid = pid;
263299c4efeSeric 	p->m_fd = fd;
26465c4fdfbSgilles }
26565c4fdfbSgilles 
26665c4fdfbSgilles void
26765c4fdfbSgilles m_add(struct mproc *p, const void *data, size_t len)
26865c4fdfbSgilles {
269299c4efeSeric 	size_t	 alloc;
270299c4efeSeric 	void	*tmp;
27165c4fdfbSgilles 
272299c4efeSeric 	if (p->m_pos + len + IMSG_HEADER_SIZE > MAX_IMSGSIZE) {
273ca0c3639Sgilles 		log_warnx("warn: message too large");
274299c4efeSeric 		fatal(NULL);
275299c4efeSeric 	}
276299c4efeSeric 
277107c21adSeric 	alloc = p->m_alloc ? p->m_alloc : 128;
278299c4efeSeric 	while (p->m_pos + len > alloc)
279299c4efeSeric 		alloc *= 2;
280299c4efeSeric 	if (alloc != p->m_alloc) {
281299c4efeSeric 		log_trace(TRACE_MPROC, "mproc: %s -> %s: realloc %zu -> %zu",
282299c4efeSeric 		    proc_name(smtpd_process),
283299c4efeSeric 		    proc_name(p->proc),
284299c4efeSeric 		    p->m_alloc,
285299c4efeSeric 		    alloc);
286299c4efeSeric 
287107c21adSeric 		tmp = recallocarray(p->m_buf, p->m_alloc, alloc, 1);
288299c4efeSeric 		if (tmp == NULL)
289299c4efeSeric 			fatal("realloc");
290299c4efeSeric 		p->m_alloc = alloc;
291299c4efeSeric 		p->m_buf = tmp;
292299c4efeSeric 	}
293299c4efeSeric 
294299c4efeSeric 	memmove(p->m_buf + p->m_pos, data, len);
295299c4efeSeric 	p->m_pos += len;
29665c4fdfbSgilles }
29765c4fdfbSgilles 
29865c4fdfbSgilles void
29965c4fdfbSgilles m_close(struct mproc *p)
30065c4fdfbSgilles {
301299c4efeSeric 	if (imsg_compose(&p->imsgbuf, p->m_type, p->m_peerid, p->m_pid, p->m_fd,
302299c4efeSeric 	    p->m_buf, p->m_pos) == -1)
303299c4efeSeric 		fatal("imsg_compose");
30465c4fdfbSgilles 
305299c4efeSeric 	log_trace(TRACE_MPROC, "mproc: %s -> %s : %zu %s",
30665c4fdfbSgilles 		    proc_name(smtpd_process),
30765c4fdfbSgilles 		    proc_name(p->proc),
308299c4efeSeric 		    p->m_pos,
309299c4efeSeric 		    imsg_to_str(p->m_type));
31065c4fdfbSgilles 
31165c4fdfbSgilles 	mproc_event_add(p);
31265c4fdfbSgilles }
31365c4fdfbSgilles 
314c4df3bf2Sreyk void
315c4df3bf2Sreyk m_flush(struct mproc *p)
316c4df3bf2Sreyk {
317c4df3bf2Sreyk 	if (imsg_compose(&p->imsgbuf, p->m_type, p->m_peerid, p->m_pid, p->m_fd,
318c4df3bf2Sreyk 	    p->m_buf, p->m_pos) == -1)
319c4df3bf2Sreyk 		fatal("imsg_compose");
320c4df3bf2Sreyk 
321c4df3bf2Sreyk 	log_trace(TRACE_MPROC, "mproc: %s -> %s : %zu %s (flush)",
322c4df3bf2Sreyk 	    proc_name(smtpd_process),
323c4df3bf2Sreyk 	    proc_name(p->proc),
324c4df3bf2Sreyk 	    p->m_pos,
325c4df3bf2Sreyk 	    imsg_to_str(p->m_type));
326c4df3bf2Sreyk 
327c4df3bf2Sreyk 	p->m_pos = 0;
328c4df3bf2Sreyk 
329dd7efffeSclaudio 	if (imsgbuf_flush(&p->imsgbuf) == -1)
330dd7efffeSclaudio 		fatal("imsgbuf_flush");
331c4df3bf2Sreyk }
332c4df3bf2Sreyk 
33365c4fdfbSgilles static struct imsg * current;
33465c4fdfbSgilles 
33565c4fdfbSgilles static void
33665c4fdfbSgilles m_error(const char *error)
33765c4fdfbSgilles {
33865c4fdfbSgilles 	char	buf[512];
33965c4fdfbSgilles 
340dd7aa8c7Sgilles 	(void)snprintf(buf, sizeof buf, "%s: %s: %s",
34165c4fdfbSgilles 	    proc_name(smtpd_process),
34265c4fdfbSgilles 	    imsg_to_str(current->hdr.type),
34365c4fdfbSgilles 	    error);
344d6f2ac01Seric 	fatalx("%s", buf);
34565c4fdfbSgilles }
34665c4fdfbSgilles 
34765c4fdfbSgilles void
34865c4fdfbSgilles m_msg(struct msg *m, struct imsg *imsg)
34965c4fdfbSgilles {
35065c4fdfbSgilles 	current = imsg;
35165c4fdfbSgilles 	m->pos = imsg->data;
35265c4fdfbSgilles 	m->end = m->pos + (imsg->hdr.len - sizeof(imsg->hdr));
35365c4fdfbSgilles }
35465c4fdfbSgilles 
35565c4fdfbSgilles void
35665c4fdfbSgilles m_end(struct msg *m)
35765c4fdfbSgilles {
35865c4fdfbSgilles 	if (m->pos != m->end)
35965c4fdfbSgilles 		m_error("not at msg end");
36065c4fdfbSgilles }
36165c4fdfbSgilles 
36265c4fdfbSgilles int
36365c4fdfbSgilles m_is_eom(struct msg *m)
36465c4fdfbSgilles {
36565c4fdfbSgilles 	return (m->pos == m->end);
36665c4fdfbSgilles }
36765c4fdfbSgilles 
36865c4fdfbSgilles static inline void
36965c4fdfbSgilles m_get(struct msg *m, void *dst, size_t sz)
37065c4fdfbSgilles {
37181a33c5dSeric 	if (sz > MAX_IMSGSIZE ||
37281a33c5dSeric 	    m->end - m->pos < (ssize_t)sz)
37381a33c5dSeric 		fatalx("msg too short");
37481a33c5dSeric 
37565c4fdfbSgilles 	memmove(dst, m->pos, sz);
37665c4fdfbSgilles 	m->pos += sz;
37765c4fdfbSgilles }
37865c4fdfbSgilles 
37965c4fdfbSgilles void
38065c4fdfbSgilles m_add_int(struct mproc *m, int v)
38165c4fdfbSgilles {
38281a33c5dSeric 	m_add(m, &v, sizeof(v));
38365c4fdfbSgilles };
38465c4fdfbSgilles 
38565c4fdfbSgilles void
38665c4fdfbSgilles m_add_u32(struct mproc *m, uint32_t u32)
38765c4fdfbSgilles {
38881a33c5dSeric 	m_add(m, &u32, sizeof(u32));
38965c4fdfbSgilles };
39065c4fdfbSgilles 
39165c4fdfbSgilles void
392c4df3bf2Sreyk m_add_size(struct mproc *m, size_t sz)
393c4df3bf2Sreyk {
39481a33c5dSeric 	m_add(m, &sz, sizeof(sz));
395c4df3bf2Sreyk };
396c4df3bf2Sreyk 
397c4df3bf2Sreyk void
39865c4fdfbSgilles m_add_time(struct mproc *m, time_t v)
39965c4fdfbSgilles {
40081a33c5dSeric 	m_add(m, &v, sizeof(v));
40165c4fdfbSgilles };
40265c4fdfbSgilles 
40365c4fdfbSgilles void
4044e92310aSgilles m_add_timeval(struct mproc *m, struct timeval *tv)
4054e92310aSgilles {
4064e92310aSgilles 	m_add(m, tv, sizeof(*tv));
4074e92310aSgilles }
4084e92310aSgilles 
4094e92310aSgilles 
4104e92310aSgilles void
41165c4fdfbSgilles m_add_string(struct mproc *m, const char *v)
41265c4fdfbSgilles {
413d6a71827Seric 	if (v) {
414d6a71827Seric 		m_add(m, "s", 1);
41581a33c5dSeric 		m_add(m, v, strlen(v) + 1);
416d6a71827Seric 	}
417d6a71827Seric 	else
418d6a71827Seric 		m_add(m, "\0", 1);
41965c4fdfbSgilles };
42065c4fdfbSgilles 
42165c4fdfbSgilles void
42265c4fdfbSgilles m_add_data(struct mproc *m, const void *v, size_t len)
42365c4fdfbSgilles {
42481a33c5dSeric 	m_add_size(m, len);
42581a33c5dSeric 	m_add(m, v, len);
42665c4fdfbSgilles };
42765c4fdfbSgilles 
42865c4fdfbSgilles void
42965c4fdfbSgilles m_add_id(struct mproc *m, uint64_t v)
43065c4fdfbSgilles {
43181a33c5dSeric 	m_add(m, &v, sizeof(v));
43265c4fdfbSgilles }
43365c4fdfbSgilles 
43465c4fdfbSgilles void
43565c4fdfbSgilles m_add_evpid(struct mproc *m, uint64_t v)
43665c4fdfbSgilles {
43781a33c5dSeric 	m_add(m, &v, sizeof(v));
43865c4fdfbSgilles }
43965c4fdfbSgilles 
44065c4fdfbSgilles void
44165c4fdfbSgilles m_add_msgid(struct mproc *m, uint32_t v)
44265c4fdfbSgilles {
44381a33c5dSeric 	m_add(m, &v, sizeof(v));
44465c4fdfbSgilles }
44565c4fdfbSgilles 
44665c4fdfbSgilles void
44765c4fdfbSgilles m_add_sockaddr(struct mproc *m, const struct sockaddr *sa)
44865c4fdfbSgilles {
44981a33c5dSeric 	m_add_size(m, sa->sa_len);
45081a33c5dSeric 	m_add(m, sa, sa->sa_len);
45165c4fdfbSgilles }
45265c4fdfbSgilles 
45365c4fdfbSgilles void
45465c4fdfbSgilles m_add_mailaddr(struct mproc *m, const struct mailaddr *maddr)
45565c4fdfbSgilles {
45681a33c5dSeric 	m_add(m, maddr, sizeof(*maddr));
45765c4fdfbSgilles }
45865c4fdfbSgilles 
45965c4fdfbSgilles void
46065c4fdfbSgilles m_add_envelope(struct mproc *m, const struct envelope *evp)
46165c4fdfbSgilles {
46265c4fdfbSgilles 	char	buf[sizeof(*evp)];
46365c4fdfbSgilles 
46465c4fdfbSgilles 	envelope_dump_buffer(evp, buf, sizeof(buf));
46565c4fdfbSgilles 	m_add_evpid(m, evp->id);
46681a33c5dSeric 	m_add_string(m, buf);
46765c4fdfbSgilles }
46865c4fdfbSgilles 
46965c4fdfbSgilles void
470d6f2ac01Seric m_add_params(struct mproc *m, struct dict *d)
471d6f2ac01Seric {
472d6f2ac01Seric 	const char *key;
473d6f2ac01Seric 	char *value;
474d6f2ac01Seric 	void *iter;
475d6f2ac01Seric 
476d6f2ac01Seric 	if (d == NULL) {
477d6f2ac01Seric 		m_add_size(m, 0);
478d6f2ac01Seric 		return;
479d6f2ac01Seric 	}
480d6f2ac01Seric 	m_add_size(m, dict_count(d));
481d6f2ac01Seric 	iter = NULL;
482d6f2ac01Seric 	while (dict_iter(d, &iter, &key, (void **)&value)) {
483d6f2ac01Seric 		m_add_string(m, key);
484d6f2ac01Seric 		m_add_string(m, value);
485d6f2ac01Seric 	}
486d6f2ac01Seric }
487d6f2ac01Seric 
488d6f2ac01Seric void
48965c4fdfbSgilles m_get_int(struct msg *m, int *i)
49065c4fdfbSgilles {
49181a33c5dSeric 	m_get(m, i, sizeof(*i));
49265c4fdfbSgilles }
49365c4fdfbSgilles 
49465c4fdfbSgilles void
49565c4fdfbSgilles m_get_u32(struct msg *m, uint32_t *u32)
49665c4fdfbSgilles {
49781a33c5dSeric 	m_get(m, u32, sizeof(*u32));
49865c4fdfbSgilles }
49965c4fdfbSgilles 
50065c4fdfbSgilles void
501c4df3bf2Sreyk m_get_size(struct msg *m, size_t *sz)
502c4df3bf2Sreyk {
50381a33c5dSeric 	m_get(m, sz, sizeof(*sz));
504c4df3bf2Sreyk }
505c4df3bf2Sreyk 
506c4df3bf2Sreyk void
50765c4fdfbSgilles m_get_time(struct msg *m, time_t *t)
50865c4fdfbSgilles {
50981a33c5dSeric 	m_get(m, t, sizeof(*t));
51065c4fdfbSgilles }
51165c4fdfbSgilles 
51265c4fdfbSgilles void
5134e92310aSgilles m_get_timeval(struct msg *m, struct timeval *tv)
5144e92310aSgilles {
5154e92310aSgilles 	m_get(m, tv, sizeof(*tv));
5164e92310aSgilles }
5174e92310aSgilles 
5184e92310aSgilles void
51965c4fdfbSgilles m_get_string(struct msg *m, const char **s)
52065c4fdfbSgilles {
52165c4fdfbSgilles 	uint8_t	*end;
522d6a71827Seric 	char c;
52365c4fdfbSgilles 
52481a33c5dSeric 	if (m->pos >= m->end)
52565c4fdfbSgilles 		m_error("msg too short");
52665c4fdfbSgilles 
527d6a71827Seric 	c = *m->pos++;
528d6a71827Seric 	if (c == '\0') {
529d6a71827Seric 		*s = NULL;
530d6a71827Seric 		return;
531d6a71827Seric 	}
532d6a71827Seric 
533d6a71827Seric 	if (m->pos >= m->end)
534d6a71827Seric 		m_error("msg too short");
53581a33c5dSeric 	end = memchr(m->pos, 0, m->end - m->pos);
53665c4fdfbSgilles 	if (end == NULL)
53765c4fdfbSgilles 		m_error("unterminated string");
53865c4fdfbSgilles 
53981a33c5dSeric 	*s = m->pos;
54065c4fdfbSgilles 	m->pos = end + 1;
54165c4fdfbSgilles }
54265c4fdfbSgilles 
54365c4fdfbSgilles void
54465c4fdfbSgilles m_get_data(struct msg *m, const void **data, size_t *sz)
54565c4fdfbSgilles {
54681a33c5dSeric 	m_get_size(m, sz);
54781a33c5dSeric 
548db2790b6Seric 	if (*sz == 0) {
549db2790b6Seric 		*data = NULL;
550db2790b6Seric 		return;
551db2790b6Seric 	}
552db2790b6Seric 
55381a33c5dSeric 	if (m->pos + *sz > m->end)
55481a33c5dSeric 		m_error("msg too short");
55581a33c5dSeric 
55681a33c5dSeric 	*data = m->pos;
55781a33c5dSeric 	m->pos += *sz;
55865c4fdfbSgilles }
55965c4fdfbSgilles 
56065c4fdfbSgilles void
56165c4fdfbSgilles m_get_evpid(struct msg *m, uint64_t *evpid)
56265c4fdfbSgilles {
56381a33c5dSeric 	m_get(m, evpid, sizeof(*evpid));
56465c4fdfbSgilles }
56565c4fdfbSgilles 
56665c4fdfbSgilles void
56765c4fdfbSgilles m_get_msgid(struct msg *m, uint32_t *msgid)
56865c4fdfbSgilles {
56981a33c5dSeric 	m_get(m, msgid, sizeof(*msgid));
57065c4fdfbSgilles }
57165c4fdfbSgilles 
57265c4fdfbSgilles void
57365c4fdfbSgilles m_get_id(struct msg *m, uint64_t *id)
57465c4fdfbSgilles {
57581a33c5dSeric 	m_get(m, id, sizeof(*id));
57665c4fdfbSgilles }
57765c4fdfbSgilles 
57865c4fdfbSgilles void
57965c4fdfbSgilles m_get_sockaddr(struct msg *m, struct sockaddr *sa)
58065c4fdfbSgilles {
58181a33c5dSeric 	size_t len;
58265c4fdfbSgilles 
58381a33c5dSeric 	m_get_size(m, &len);
58481a33c5dSeric 	m_get(m, sa, len);
58565c4fdfbSgilles }
58665c4fdfbSgilles 
58765c4fdfbSgilles void
58865c4fdfbSgilles m_get_mailaddr(struct msg *m, struct mailaddr *maddr)
58965c4fdfbSgilles {
59081a33c5dSeric 	m_get(m, maddr, sizeof(*maddr));
59165c4fdfbSgilles }
59265c4fdfbSgilles 
59365c4fdfbSgilles void
59465c4fdfbSgilles m_get_envelope(struct msg *m, struct envelope *evp)
59565c4fdfbSgilles {
59665c4fdfbSgilles 	uint64_t	 evpid;
59781a33c5dSeric 	const char	*buf;
59865c4fdfbSgilles 
59965c4fdfbSgilles 	m_get_evpid(m, &evpid);
60081a33c5dSeric 	m_get_string(m, &buf);
60191145277Stobhe 	if (buf == NULL)
60291145277Stobhe 		fatalx("empty envelope buffer");
60365c4fdfbSgilles 
60481a33c5dSeric 	if (!envelope_load_buffer(evp, buf, strlen(buf)))
6054e5d6ca2Seric 		fatalx("failed to retrieve envelope");
60665c4fdfbSgilles 	evp->id = evpid;
60765c4fdfbSgilles }
608d6f2ac01Seric 
609d6f2ac01Seric void
610d6f2ac01Seric m_get_params(struct msg *m, struct dict *d)
611d6f2ac01Seric {
612d6f2ac01Seric 	size_t	c;
613d6f2ac01Seric 	const char *key;
614d6f2ac01Seric 	const char *value;
615d6f2ac01Seric 	char *tmp;
616d6f2ac01Seric 
617d6f2ac01Seric 	dict_init(d);
618d6f2ac01Seric 
619d6f2ac01Seric 	m_get_size(m, &c);
620d6f2ac01Seric 
621d6f2ac01Seric 	for (; c; c--) {
622d6f2ac01Seric 		m_get_string(m, &key);
623d6f2ac01Seric 		m_get_string(m, &value);
624d6f2ac01Seric 		if ((tmp = strdup(value)) == NULL)
625d6f2ac01Seric 			fatal("m_get_params");
626d6f2ac01Seric 		dict_set(d, key, tmp);
627d6f2ac01Seric 	}
628d6f2ac01Seric }
629d6f2ac01Seric 
630d6f2ac01Seric void
631d6f2ac01Seric m_clear_params(struct dict *d)
632d6f2ac01Seric {
633d6f2ac01Seric 	char *value;
634d6f2ac01Seric 
635d6f2ac01Seric 	while (dict_poproot(d, (void **)&value))
636d6f2ac01Seric 		free(value);
637d6f2ac01Seric }
638