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