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