xref: /openbsd/usr.sbin/rpki-client/io.c (revision 929d2bb2)
1 /*	$OpenBSD: io.c,v 1.27 2024/11/26 13:59:09 claudio Exp $ */
2 /*
3  * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
4  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/queue.h>
20 #include <sys/socket.h>
21 
22 #include <err.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <stdint.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <imsg.h>
30 
31 #include "extern.h"
32 
33 #define IO_FD_MARK	0x80000000U
34 
35 /*
36  * Create new io buffer, call io_close() when done with it.
37  * Function always returns a new buffer.
38  */
39 struct ibuf *
io_new_buffer(void)40 io_new_buffer(void)
41 {
42 	struct ibuf *b;
43 
44 	if ((b = ibuf_dynamic(64, MAX_MSG_SIZE)) == NULL)
45 		err(1, NULL);
46 	ibuf_add_zero(b, sizeof(size_t));	/* can not fail */
47 	return b;
48 }
49 
50 /*
51  * Add a simple object of static size to the io buffer.
52  */
53 void
io_simple_buffer(struct ibuf * b,const void * res,size_t sz)54 io_simple_buffer(struct ibuf *b, const void *res, size_t sz)
55 {
56 	if (ibuf_add(b, res, sz) == -1)
57 		err(1, NULL);
58 }
59 
60 /*
61  * Add a sz sized buffer into the io buffer.
62  */
63 void
io_buf_buffer(struct ibuf * b,const void * p,size_t sz)64 io_buf_buffer(struct ibuf *b, const void *p, size_t sz)
65 {
66 	if (ibuf_add(b, &sz, sizeof(size_t)) == -1)
67 		err(1, NULL);
68 	if (sz > 0)
69 		if (ibuf_add(b, p, sz) == -1)
70 			err(1, NULL);
71 }
72 
73 /*
74  * Add a string into the io buffer.
75  */
76 void
io_str_buffer(struct ibuf * b,const char * p)77 io_str_buffer(struct ibuf *b, const char *p)
78 {
79 	size_t sz = (p == NULL) ? 0 : strlen(p);
80 
81 	io_buf_buffer(b, p, sz);
82 }
83 
84 /*
85  * Finish and enqueue a io buffer.
86  */
87 void
io_close_buffer(struct msgbuf * msgbuf,struct ibuf * b)88 io_close_buffer(struct msgbuf *msgbuf, struct ibuf *b)
89 {
90 	size_t len;
91 
92 	len = ibuf_size(b);
93 	if (ibuf_fd_avail(b))
94 		len |= IO_FD_MARK;
95 	ibuf_set(b, 0, &len, sizeof(len));
96 	ibuf_close(msgbuf, b);
97 }
98 
99 /*
100  * Read of an ibuf and extract sz byte from there.
101  * Does nothing if "sz" is zero.
102  * Return 1 on success or 0 if there was not enough data.
103  */
104 void
io_read_buf(struct ibuf * b,void * res,size_t sz)105 io_read_buf(struct ibuf *b, void *res, size_t sz)
106 {
107 	if (sz == 0)
108 		return;
109 	if (ibuf_get(b, res, sz) == -1)
110 		err(1, "bad internal framing");
111 }
112 
113 /*
114  * Read a string (returns NULL for zero-length strings), allocating
115  * space for it.
116  * Return 1 on success or 0 if there was not enough data.
117  */
118 void
io_read_str(struct ibuf * b,char ** res)119 io_read_str(struct ibuf *b, char **res)
120 {
121 	size_t	 sz;
122 
123 	io_read_buf(b, &sz, sizeof(sz));
124 	if (sz == 0) {
125 		*res = NULL;
126 		return;
127 	}
128 	if ((*res = calloc(sz + 1, 1)) == NULL)
129 		err(1, NULL);
130 	io_read_buf(b, *res, sz);
131 }
132 
133 /*
134  * Read a binary buffer, allocating space for it.
135  * If the buffer is zero-sized, this won't allocate "res", but
136  * will still initialise it to NULL.
137  * Return 1 on success or 0 if there was not enough data.
138  */
139 void
io_read_buf_alloc(struct ibuf * b,void ** res,size_t * sz)140 io_read_buf_alloc(struct ibuf *b, void **res, size_t *sz)
141 {
142 	*res = NULL;
143 	io_read_buf(b, sz, sizeof(*sz));
144 	if (*sz == 0)
145 		return;
146 	if ((*res = malloc(*sz)) == NULL)
147 		err(1, NULL);
148 	io_read_buf(b, *res, *sz);
149 }
150 
151 struct ibuf *
io_parse_hdr(struct ibuf * buf,void * arg,int * fd)152 io_parse_hdr(struct ibuf *buf, void *arg, int *fd)
153 {
154 	struct ibuf *b;
155 	size_t len;
156 	int hasfd = 0;
157 
158 	if (ibuf_get(buf, &len, sizeof(len)) == -1)
159 		return NULL;
160 
161 	if (len & IO_FD_MARK) {
162 		hasfd = 1;
163 		len &= ~IO_FD_MARK;
164 	}
165 	if (len <= sizeof(len) || len > MAX_MSG_SIZE) {
166 		errno = ERANGE;
167 		return NULL;
168 	}
169 	if ((b = ibuf_open(len)) == NULL)
170 		return NULL;
171 	if (hasfd) {
172 		ibuf_fd_set(b, *fd);
173 		*fd = -1;
174 	}
175 	return b;
176 }
177 
178 struct ibuf *
io_buf_get(struct msgbuf * msgq)179 io_buf_get(struct msgbuf *msgq)
180 {
181 	struct ibuf *b;
182 
183 	if ((b = msgbuf_get(msgq)) == NULL)
184 		return NULL;
185 
186 	ibuf_skip(b, sizeof(size_t));
187 	return b;
188 }
189