xref: /openbsd/usr.sbin/rpki-client/io.c (revision 929d2bb2)
1*929d2bb2Sclaudio /*	$OpenBSD: io.c,v 1.27 2024/11/26 13:59:09 claudio Exp $ */
29a7e9e7fSjob /*
3a945dbeeSclaudio  * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
49a7e9e7fSjob  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
59a7e9e7fSjob  *
69a7e9e7fSjob  * Permission to use, copy, modify, and distribute this software for any
79a7e9e7fSjob  * purpose with or without fee is hereby granted, provided that the above
89a7e9e7fSjob  * copyright notice and this permission notice appear in all copies.
99a7e9e7fSjob  *
109a7e9e7fSjob  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
119a7e9e7fSjob  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
129a7e9e7fSjob  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
139a7e9e7fSjob  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
149a7e9e7fSjob  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
159a7e9e7fSjob  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
169a7e9e7fSjob  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
179a7e9e7fSjob  */
189a7e9e7fSjob 
199a7e9e7fSjob #include <sys/queue.h>
201ef5b48aSclaudio #include <sys/socket.h>
219a7e9e7fSjob 
229a7e9e7fSjob #include <err.h>
231ef5b48aSclaudio #include <errno.h>
249a7e9e7fSjob #include <fcntl.h>
259a7e9e7fSjob #include <stdint.h>
269a7e9e7fSjob #include <stdlib.h>
279a7e9e7fSjob #include <string.h>
289a7e9e7fSjob #include <unistd.h>
2908db1177Sclaudio #include <imsg.h>
309a7e9e7fSjob 
319a7e9e7fSjob #include "extern.h"
329a7e9e7fSjob 
33*929d2bb2Sclaudio #define IO_FD_MARK	0x80000000U
34*929d2bb2Sclaudio 
359a7e9e7fSjob /*
362defcb52Sclaudio  * Create new io buffer, call io_close() when done with it.
372defcb52Sclaudio  * Function always returns a new buffer.
382defcb52Sclaudio  */
392defcb52Sclaudio struct ibuf *
io_new_buffer(void)4025f7afeeSclaudio io_new_buffer(void)
412defcb52Sclaudio {
422defcb52Sclaudio 	struct ibuf *b;
432defcb52Sclaudio 
44b5fa5d51Sclaudio 	if ((b = ibuf_dynamic(64, MAX_MSG_SIZE)) == NULL)
452defcb52Sclaudio 		err(1, NULL);
46cf954fffSclaudio 	ibuf_add_zero(b, sizeof(size_t));	/* can not fail */
472defcb52Sclaudio 	return b;
482defcb52Sclaudio }
492defcb52Sclaudio 
502defcb52Sclaudio /*
512defcb52Sclaudio  * Add a simple object of static size to the io buffer.
529a7e9e7fSjob  */
539a7e9e7fSjob void
io_simple_buffer(struct ibuf * b,const void * res,size_t sz)5408db1177Sclaudio io_simple_buffer(struct ibuf *b, const void *res, size_t sz)
559a7e9e7fSjob {
5608db1177Sclaudio 	if (ibuf_add(b, res, sz) == -1)
57498a9228Sbenno 		err(1, NULL);
589a7e9e7fSjob }
599a7e9e7fSjob 
609a7e9e7fSjob /*
6108db1177Sclaudio  * Add a sz sized buffer into the io buffer.
629a7e9e7fSjob  */
639a7e9e7fSjob void
io_buf_buffer(struct ibuf * b,const void * p,size_t sz)6408db1177Sclaudio io_buf_buffer(struct ibuf *b, const void *p, size_t sz)
659a7e9e7fSjob {
6608db1177Sclaudio 	if (ibuf_add(b, &sz, sizeof(size_t)) == -1)
6708db1177Sclaudio 		err(1, NULL);
689a7e9e7fSjob 	if (sz > 0)
6908db1177Sclaudio 		if (ibuf_add(b, p, sz) == -1)
7008db1177Sclaudio 			err(1, NULL);
719a7e9e7fSjob }
729a7e9e7fSjob 
739a7e9e7fSjob /*
7408db1177Sclaudio  * Add a string into the io buffer.
759a7e9e7fSjob  */
769a7e9e7fSjob void
io_str_buffer(struct ibuf * b,const char * p)7708db1177Sclaudio io_str_buffer(struct ibuf *b, const char *p)
789a7e9e7fSjob {
799a7e9e7fSjob 	size_t sz = (p == NULL) ? 0 : strlen(p);
809a7e9e7fSjob 
8108db1177Sclaudio 	io_buf_buffer(b, p, sz);
829a7e9e7fSjob }
839a7e9e7fSjob 
849a7e9e7fSjob /*
852defcb52Sclaudio  * Finish and enqueue a io buffer.
862defcb52Sclaudio  */
872defcb52Sclaudio void
io_close_buffer(struct msgbuf * msgbuf,struct ibuf * b)8825f7afeeSclaudio io_close_buffer(struct msgbuf *msgbuf, struct ibuf *b)
892defcb52Sclaudio {
902defcb52Sclaudio 	size_t len;
912defcb52Sclaudio 
92b5fa5d51Sclaudio 	len = ibuf_size(b);
93*929d2bb2Sclaudio 	if (ibuf_fd_avail(b))
94*929d2bb2Sclaudio 		len |= IO_FD_MARK;
95cf954fffSclaudio 	ibuf_set(b, 0, &len, sizeof(len));
962defcb52Sclaudio 	ibuf_close(msgbuf, b);
972defcb52Sclaudio }
982defcb52Sclaudio 
992defcb52Sclaudio /*
1007eb79a4aSclaudio  * Read of an ibuf and extract sz byte from there.
1019a7e9e7fSjob  * Does nothing if "sz" is zero.
1027eb79a4aSclaudio  * Return 1 on success or 0 if there was not enough data.
1039a7e9e7fSjob  */
1049a7e9e7fSjob void
io_read_buf(struct ibuf * b,void * res,size_t sz)1057eb79a4aSclaudio io_read_buf(struct ibuf *b, void *res, size_t sz)
1069a7e9e7fSjob {
1079a7e9e7fSjob 	if (sz == 0)
1089a7e9e7fSjob 		return;
109edece116Sclaudio 	if (ibuf_get(b, res, sz) == -1)
110edece116Sclaudio 		err(1, "bad internal framing");
1119a7e9e7fSjob }
1129a7e9e7fSjob 
1139a7e9e7fSjob /*
11445a66391Sclaudio  * Read a string (returns NULL for zero-length strings), allocating
1159a7e9e7fSjob  * space for it.
1167eb79a4aSclaudio  * Return 1 on success or 0 if there was not enough data.
1179a7e9e7fSjob  */
1189a7e9e7fSjob void
io_read_str(struct ibuf * b,char ** res)1197eb79a4aSclaudio io_read_str(struct ibuf *b, char **res)
1209a7e9e7fSjob {
1219a7e9e7fSjob 	size_t	 sz;
1229a7e9e7fSjob 
1237eb79a4aSclaudio 	io_read_buf(b, &sz, sizeof(sz));
12445a66391Sclaudio 	if (sz == 0) {
12545a66391Sclaudio 		*res = NULL;
12645a66391Sclaudio 		return;
12745a66391Sclaudio 	}
1289a7e9e7fSjob 	if ((*res = calloc(sz + 1, 1)) == NULL)
129498a9228Sbenno 		err(1, NULL);
1307eb79a4aSclaudio 	io_read_buf(b, *res, sz);
1319a7e9e7fSjob }
1321ef5b48aSclaudio 
1331ef5b48aSclaudio /*
1347eb79a4aSclaudio  * Read a binary buffer, allocating space for it.
1357eb79a4aSclaudio  * If the buffer is zero-sized, this won't allocate "res", but
1367eb79a4aSclaudio  * will still initialise it to NULL.
1377eb79a4aSclaudio  * Return 1 on success or 0 if there was not enough data.
1387eb79a4aSclaudio  */
1397eb79a4aSclaudio void
io_read_buf_alloc(struct ibuf * b,void ** res,size_t * sz)1407eb79a4aSclaudio io_read_buf_alloc(struct ibuf *b, void **res, size_t *sz)
1417eb79a4aSclaudio {
1427eb79a4aSclaudio 	*res = NULL;
1435ef05219Sjsg 	io_read_buf(b, sz, sizeof(*sz));
1447eb79a4aSclaudio 	if (*sz == 0)
1457eb79a4aSclaudio 		return;
1467eb79a4aSclaudio 	if ((*res = malloc(*sz)) == NULL)
1477eb79a4aSclaudio 		err(1, NULL);
1487eb79a4aSclaudio 	io_read_buf(b, *res, *sz);
1497eb79a4aSclaudio }
1507eb79a4aSclaudio 
151*929d2bb2Sclaudio struct ibuf *
io_parse_hdr(struct ibuf * buf,void * arg,int * fd)152*929d2bb2Sclaudio io_parse_hdr(struct ibuf *buf, void *arg, int *fd)
1537eb79a4aSclaudio {
154*929d2bb2Sclaudio 	struct ibuf *b;
155*929d2bb2Sclaudio 	size_t len;
156*929d2bb2Sclaudio 	int hasfd = 0;
1577eb79a4aSclaudio 
158*929d2bb2Sclaudio 	if (ibuf_get(buf, &len, sizeof(len)) == -1)
159*929d2bb2Sclaudio 		return NULL;
160*929d2bb2Sclaudio 
161*929d2bb2Sclaudio 	if (len & IO_FD_MARK) {
162*929d2bb2Sclaudio 		hasfd = 1;
163*929d2bb2Sclaudio 		len &= ~IO_FD_MARK;
164b5fa5d51Sclaudio 	}
165*929d2bb2Sclaudio 	if (len <= sizeof(len) || len > MAX_MSG_SIZE) {
166*929d2bb2Sclaudio 		errno = ERANGE;
167*929d2bb2Sclaudio 		return NULL;
168*929d2bb2Sclaudio 	}
169*929d2bb2Sclaudio 	if ((b = ibuf_open(len)) == NULL)
170*929d2bb2Sclaudio 		return NULL;
171*929d2bb2Sclaudio 	if (hasfd) {
172*929d2bb2Sclaudio 		ibuf_fd_set(b, *fd);
173*929d2bb2Sclaudio 		*fd = -1;
174*929d2bb2Sclaudio 	}
175*929d2bb2Sclaudio 	return b;
1767eb79a4aSclaudio }
1777eb79a4aSclaudio 
1787eb79a4aSclaudio struct ibuf *
io_buf_get(struct msgbuf * msgq)179b5fa5d51Sclaudio io_buf_get(struct msgbuf *msgq)
1807eb79a4aSclaudio {
181b5fa5d51Sclaudio 	struct ibuf *b;
1827eb79a4aSclaudio 
183b5fa5d51Sclaudio 	if ((b = msgbuf_get(msgq)) == NULL)
18497f73431Sclaudio 		return NULL;
1857eb79a4aSclaudio 
186b5fa5d51Sclaudio 	ibuf_skip(b, sizeof(size_t));
1877eb79a4aSclaudio 	return b;
1887eb79a4aSclaudio }
189