1 /* $OpenBSD: table_proc.c,v 1.6 2015/12/05 13:14:21 claudio 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 void * 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), "table_proc_open"); 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 return (priv); 143 } 144 145 static int 146 table_proc_update(struct table *table) 147 { 148 struct table_proc_priv *priv = table->t_handle; 149 int r; 150 151 imsg_compose(&priv->ibuf, PROC_TABLE_UPDATE, 0, 0, -1, NULL, 0); 152 153 table_proc_call(priv); 154 table_proc_read(&r, sizeof(r)); 155 table_proc_end(); 156 157 return (r); 158 } 159 160 static void 161 table_proc_close(void *arg) 162 { 163 struct table_proc_priv *priv = arg; 164 165 imsg_compose(&priv->ibuf, PROC_TABLE_CLOSE, 0, 0, -1, NULL, 0); 166 imsg_flush(&priv->ibuf); 167 } 168 169 static int 170 imsg_add_params(struct ibuf *buf, struct dict *params) 171 { 172 size_t count; 173 const char *key; 174 char *value; 175 void *iter; 176 177 count = 0; 178 if (params) 179 count = dict_count(params); 180 181 if (imsg_add(buf, &count, sizeof(count)) == -1) 182 return (-1); 183 184 if (count == 0) 185 return (0); 186 187 iter = NULL; 188 while (dict_iter(params, &iter, &key, (void **)&value)) { 189 if (imsg_add(buf, key, strlen(key) + 1) == -1) 190 return (-1); 191 if (imsg_add(buf, value, strlen(value) + 1) == -1) 192 return (-1); 193 } 194 195 return (0); 196 } 197 198 static int 199 table_proc_lookup(void *arg, struct dict *params, const char *k, enum table_service s, 200 union lookup *lk) 201 { 202 struct table_proc_priv *priv = arg; 203 struct ibuf *buf; 204 int r; 205 206 buf = imsg_create(&priv->ibuf, 207 lk ? PROC_TABLE_LOOKUP : PROC_TABLE_CHECK, 0, 0, 208 sizeof(s) + strlen(k) + 1); 209 210 if (buf == NULL) 211 return (-1); 212 if (imsg_add(buf, &s, sizeof(s)) == -1) 213 return (-1); 214 if (imsg_add_params(buf, params) == -1) 215 return (-1); 216 if (imsg_add(buf, k, strlen(k) + 1) == -1) 217 return (-1); 218 imsg_close(&priv->ibuf, buf); 219 220 table_proc_call(priv); 221 table_proc_read(&r, sizeof(r)); 222 223 if (r == 1 && lk) { 224 if (rlen == 0) { 225 log_warnx("warn: table-proc: empty response"); 226 fatalx("table-proc: exiting"); 227 } 228 if (rdata[rlen - 1] != '\0') { 229 log_warnx("warn: table-proc: not NUL-terminated"); 230 fatalx("table-proc: exiting"); 231 } 232 r = table_parse_lookup(s, k, rdata, lk); 233 table_proc_read(NULL, rlen); 234 } 235 236 table_proc_end(); 237 238 return (r); 239 } 240 241 static int 242 table_proc_fetch(void *arg, struct dict *params, enum table_service s, union lookup *lk) 243 { 244 struct table_proc_priv *priv = arg; 245 struct ibuf *buf; 246 int r; 247 248 buf = imsg_create(&priv->ibuf, PROC_TABLE_FETCH, 0, 0, sizeof(s)); 249 if (buf == NULL) 250 return (-1); 251 if (imsg_add(buf, &s, sizeof(s)) == -1) 252 return (-1); 253 if (imsg_add_params(buf, params) == -1) 254 return (-1); 255 imsg_close(&priv->ibuf, buf); 256 257 table_proc_call(priv); 258 table_proc_read(&r, sizeof(r)); 259 260 if (r == 1) { 261 if (rlen == 0) { 262 log_warnx("warn: table-proc: empty response"); 263 fatalx("table-proc: exiting"); 264 } 265 if (rdata[rlen - 1] != '\0') { 266 log_warnx("warn: table-proc: not NUL-terminated"); 267 fatalx("table-proc: exiting"); 268 } 269 r = table_parse_lookup(s, NULL, rdata, lk); 270 table_proc_read(NULL, rlen); 271 } 272 273 table_proc_end(); 274 275 return (r); 276 } 277 278 struct table_backend table_backend_proc = { 279 K_ANY, 280 NULL, 281 table_proc_open, 282 table_proc_update, 283 table_proc_close, 284 table_proc_lookup, 285 table_proc_fetch, 286 }; 287