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