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