xref: /openbsd/usr.sbin/smtpd/table_proc.c (revision 73471bf0)
1 /*	$OpenBSD: table_proc.c,v 1.17 2021/06/14 17:58:16 eric Exp $	*/
2 
3 /*
4  * Copyright (c) 2013 Eric Faurot <eric@openbsd.org>
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 <errno.h>
20 #include <string.h>
21 
22 #include "smtpd.h"
23 #include "log.h"
24 
25 struct table_proc_priv {
26 	pid_t		pid;
27 	struct imsgbuf	ibuf;
28 };
29 
30 static struct imsg	 imsg;
31 static size_t		 rlen;
32 static char		*rdata;
33 
34 extern char	**environ;
35 
36 static void
37 table_proc_call(struct table_proc_priv *p)
38 {
39 	ssize_t	n;
40 
41 	if (imsg_flush(&p->ibuf) == -1) {
42 		log_warn("warn: table-proc: imsg_flush");
43 		fatalx("table-proc: exiting");
44 	}
45 
46 	while (1) {
47 		if ((n = imsg_get(&p->ibuf, &imsg)) == -1) {
48 			log_warn("warn: table-proc: imsg_get");
49 			break;
50 		}
51 		if (n) {
52 			rlen = imsg.hdr.len - IMSG_HEADER_SIZE;
53 			rdata = imsg.data;
54 
55 			if (imsg.hdr.type != PROC_TABLE_OK) {
56 				log_warnx("warn: table-proc: bad response");
57 				break;
58 			}
59 			return;
60 		}
61 
62 		if ((n = imsg_read(&p->ibuf)) == -1 && errno != EAGAIN) {
63 			log_warn("warn: table-proc: imsg_read");
64 			break;
65 		}
66 
67 		if (n == 0) {
68 			log_warnx("warn: table-proc: pipe closed");
69 			break;
70 		}
71 	}
72 
73 	fatalx("table-proc: exiting");
74 }
75 
76 static void
77 table_proc_read(void *dst, size_t len)
78 {
79 	if (len > rlen) {
80 		log_warnx("warn: table-proc: bad msg len");
81 		fatalx("table-proc: exiting");
82 	}
83 
84 	if (dst)
85 		memmove(dst, rdata, len);
86 
87 	rlen -= len;
88 	rdata += len;
89 }
90 
91 static void
92 table_proc_end(void)
93 {
94 	if (rlen) {
95 		log_warnx("warn: table-proc: bogus data");
96 		fatalx("table-proc: exiting");
97 	}
98 	imsg_free(&imsg);
99 }
100 
101 /*
102  * API
103  */
104 
105 static int
106 table_proc_open(struct table *table)
107 {
108 	struct table_proc_priv	*priv;
109 	struct table_open_params op;
110 	int			 fd;
111 
112 	priv = xcalloc(1, sizeof(*priv));
113 
114 	fd = fork_proc_backend("table", table->t_config, table->t_name);
115 	if (fd == -1)
116 		fatalx("table-proc: exiting");
117 
118 	imsg_init(&priv->ibuf, fd);
119 
120 	memset(&op, 0, sizeof op);
121 	op.version = PROC_TABLE_API_VERSION;
122 	(void)strlcpy(op.name, table->t_name, sizeof op.name);
123 	imsg_compose(&priv->ibuf, PROC_TABLE_OPEN, 0, 0, -1, &op, sizeof op);
124 
125 	table_proc_call(priv);
126 	table_proc_end();
127 
128 	table->t_handle = priv;
129 
130 	return (1);
131 }
132 
133 static int
134 table_proc_update(struct table *table)
135 {
136 	struct table_proc_priv	*priv = table->t_handle;
137 	int r;
138 
139 	imsg_compose(&priv->ibuf, PROC_TABLE_UPDATE, 0, 0, -1, NULL, 0);
140 
141 	table_proc_call(priv);
142 	table_proc_read(&r, sizeof(r));
143 	table_proc_end();
144 
145 	return (r);
146 }
147 
148 static void
149 table_proc_close(struct table *table)
150 {
151 	struct table_proc_priv	*priv = table->t_handle;
152 
153 	imsg_compose(&priv->ibuf, PROC_TABLE_CLOSE, 0, 0, -1, NULL, 0);
154 	if (imsg_flush(&priv->ibuf) == -1)
155 		fatal("imsg_flush");
156 
157 	table->t_handle = NULL;
158 }
159 
160 static int
161 imsg_add_params(struct ibuf *buf)
162 {
163 	size_t count = 0;
164 
165 	if (imsg_add(buf, &count, sizeof(count)) == -1)
166 		return (-1);
167 
168 	return (0);
169 }
170 
171 static int
172 table_proc_lookup(struct table *table, enum table_service s, const char *k, char **dst)
173 {
174 	struct table_proc_priv	*priv = table->t_handle;
175 	struct ibuf		*buf;
176 	int			 r;
177 
178 	buf = imsg_create(&priv->ibuf,
179 	    dst ? PROC_TABLE_LOOKUP : PROC_TABLE_CHECK, 0, 0,
180 	    sizeof(s) + strlen(k) + 1);
181 
182 	if (buf == NULL)
183 		return (-1);
184 	if (imsg_add(buf, &s, sizeof(s)) == -1)
185 		return (-1);
186 	if (imsg_add_params(buf) == -1)
187 		return (-1);
188 	if (imsg_add(buf, k, strlen(k) + 1) == -1)
189 		return (-1);
190 	imsg_close(&priv->ibuf, buf);
191 
192 	table_proc_call(priv);
193 	table_proc_read(&r, sizeof(r));
194 
195 	if (r == 1 && dst) {
196 		if (rlen == 0) {
197 			log_warnx("warn: table-proc: empty response");
198 			fatalx("table-proc: exiting");
199 		}
200 		if (rdata[rlen - 1] != '\0') {
201 			log_warnx("warn: table-proc: not NUL-terminated");
202 			fatalx("table-proc: exiting");
203 		}
204 		*dst = strdup(rdata);
205 		if (*dst == NULL)
206 			r = -1;
207 		table_proc_read(NULL, rlen);
208 	}
209 
210 	table_proc_end();
211 
212 	return (r);
213 }
214 
215 static int
216 table_proc_fetch(struct table *table, enum table_service s, char **dst)
217 {
218 	struct table_proc_priv	*priv = table->t_handle;
219 	struct ibuf		*buf;
220 	int			 r;
221 
222 	buf = imsg_create(&priv->ibuf, PROC_TABLE_FETCH, 0, 0, sizeof(s));
223 	if (buf == NULL)
224 		return (-1);
225 	if (imsg_add(buf, &s, sizeof(s)) == -1)
226 		return (-1);
227 	if (imsg_add_params(buf) == -1)
228 		return (-1);
229 	imsg_close(&priv->ibuf, buf);
230 
231 	table_proc_call(priv);
232 	table_proc_read(&r, sizeof(r));
233 
234 	if (r == 1) {
235 		if (rlen == 0) {
236 			log_warnx("warn: table-proc: empty response");
237 			fatalx("table-proc: exiting");
238 		}
239 		if (rdata[rlen - 1] != '\0') {
240 			log_warnx("warn: table-proc: not NUL-terminated");
241 			fatalx("table-proc: exiting");
242 		}
243 		*dst = strdup(rdata);
244 		if (*dst == NULL)
245 			r = -1;
246 		table_proc_read(NULL, rlen);
247 	}
248 
249 	table_proc_end();
250 
251 	return (r);
252 }
253 
254 struct table_backend table_backend_proc = {
255 	"proc",
256 	K_ANY,
257 	NULL,
258 	NULL,
259 	NULL,
260 	table_proc_open,
261 	table_proc_update,
262 	table_proc_close,
263 	table_proc_lookup,
264 	table_proc_fetch,
265 };
266