1 /* $OpenBSD: queue_ram.c,v 1.9 2018/12/30 23:09:58 guenther Exp $ */ 2 3 /* 4 * Copyright (c) 2012 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 #include <sys/stat.h> 24 25 #include <ctype.h> 26 #include <err.h> 27 #include <errno.h> 28 #include <event.h> 29 #include <fcntl.h> 30 #include <imsg.h> 31 #include <inttypes.h> 32 #include <pwd.h> 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <time.h> 37 #include <unistd.h> 38 #include <limits.h> 39 40 #include "smtpd.h" 41 #include "log.h" 42 43 struct qr_envelope { 44 char *buf; 45 size_t len; 46 }; 47 48 struct qr_message { 49 char *buf; 50 size_t len; 51 struct tree envelopes; 52 }; 53 54 static struct tree messages; 55 56 static struct qr_message * 57 get_message(uint32_t msgid) 58 { 59 struct qr_message *msg; 60 61 msg = tree_get(&messages, msgid); 62 if (msg == NULL) 63 log_warn("warn: queue-ram: message not found"); 64 65 return (msg); 66 } 67 68 static int 69 queue_ram_message_create(uint32_t *msgid) 70 { 71 struct qr_message *msg; 72 73 msg = calloc(1, sizeof(*msg)); 74 if (msg == NULL) { 75 log_warn("warn: queue-ram: calloc"); 76 return (0); 77 } 78 tree_init(&msg->envelopes); 79 80 do { 81 *msgid = queue_generate_msgid(); 82 } while (tree_check(&messages, *msgid)); 83 84 tree_xset(&messages, *msgid, msg); 85 86 return (1); 87 } 88 89 static int 90 queue_ram_message_commit(uint32_t msgid, const char *path) 91 { 92 struct qr_message *msg; 93 struct stat sb; 94 size_t n; 95 FILE *f; 96 int ret; 97 98 if ((msg = tree_get(&messages, msgid)) == NULL) { 99 log_warnx("warn: queue-ram: msgid not found"); 100 return (0); 101 } 102 103 f = fopen(path, "rb"); 104 if (f == NULL) { 105 log_warn("warn: queue-ram: fopen: %s", path); 106 return (0); 107 } 108 if (fstat(fileno(f), &sb) == -1) { 109 log_warn("warn: queue-ram: fstat"); 110 fclose(f); 111 return (0); 112 } 113 114 msg->len = sb.st_size; 115 msg->buf = malloc(msg->len); 116 if (msg->buf == NULL) { 117 log_warn("warn: queue-ram: malloc"); 118 fclose(f); 119 return (0); 120 } 121 122 ret = 0; 123 n = fread(msg->buf, 1, msg->len, f); 124 if (ferror(f)) 125 log_warn("warn: queue-ram: fread"); 126 else if ((off_t)n != sb.st_size) 127 log_warnx("warn: queue-ram: bad read"); 128 else { 129 ret = 1; 130 stat_increment("queue.ram.message.size", msg->len); 131 } 132 fclose(f); 133 134 return (ret); 135 } 136 137 static int 138 queue_ram_message_delete(uint32_t msgid) 139 { 140 struct qr_message *msg; 141 struct qr_envelope *evp; 142 uint64_t evpid; 143 144 if ((msg = tree_pop(&messages, msgid)) == NULL) { 145 log_warnx("warn: queue-ram: not found"); 146 return (0); 147 } 148 while (tree_poproot(&messages, &evpid, (void**)&evp)) { 149 stat_decrement("queue.ram.envelope.size", evp->len); 150 free(evp->buf); 151 free(evp); 152 } 153 stat_decrement("queue.ram.message.size", msg->len); 154 free(msg->buf); 155 free(msg); 156 return (0); 157 } 158 159 static int 160 queue_ram_message_fd_r(uint32_t msgid) 161 { 162 struct qr_message *msg; 163 size_t n; 164 FILE *f; 165 int fd, fd2; 166 167 if ((msg = tree_get(&messages, msgid)) == NULL) { 168 log_warnx("warn: queue-ram: not found"); 169 return (-1); 170 } 171 172 fd = mktmpfile(); 173 if (fd == -1) { 174 log_warn("warn: queue-ram: mktmpfile"); 175 return (-1); 176 } 177 178 fd2 = dup(fd); 179 if (fd2 == -1) { 180 log_warn("warn: queue-ram: dup"); 181 close(fd); 182 return (-1); 183 } 184 f = fdopen(fd2, "w"); 185 if (f == NULL) { 186 log_warn("warn: queue-ram: fdopen"); 187 close(fd); 188 close(fd2); 189 return (-1); 190 } 191 n = fwrite(msg->buf, 1, msg->len, f); 192 if (n != msg->len) { 193 log_warn("warn: queue-ram: write"); 194 close(fd); 195 fclose(f); 196 return (-1); 197 } 198 fclose(f); 199 lseek(fd, 0, SEEK_SET); 200 return (fd); 201 } 202 203 static int 204 queue_ram_envelope_create(uint32_t msgid, const char *buf, size_t len, 205 uint64_t *evpid) 206 { 207 struct qr_envelope *evp; 208 struct qr_message *msg; 209 210 if ((msg = get_message(msgid)) == NULL) 211 return (0); 212 213 do { 214 *evpid = queue_generate_evpid(msgid); 215 } while (tree_check(&msg->envelopes, *evpid)); 216 evp = calloc(1, sizeof *evp); 217 if (evp == NULL) { 218 log_warn("warn: queue-ram: calloc"); 219 return (0); 220 } 221 evp->len = len; 222 evp->buf = malloc(len); 223 if (evp->buf == NULL) { 224 log_warn("warn: queue-ram: malloc"); 225 free(evp); 226 return (0); 227 } 228 memmove(evp->buf, buf, len); 229 tree_xset(&msg->envelopes, *evpid, evp); 230 stat_increment("queue.ram.envelope.size", len); 231 return (1); 232 } 233 234 static int 235 queue_ram_envelope_delete(uint64_t evpid) 236 { 237 struct qr_envelope *evp; 238 struct qr_message *msg; 239 240 if ((msg = get_message(evpid_to_msgid(evpid))) == NULL) 241 return (0); 242 243 if ((evp = tree_pop(&msg->envelopes, evpid)) == NULL) { 244 log_warnx("warn: queue-ram: not found"); 245 return (0); 246 } 247 stat_decrement("queue.ram.envelope.size", evp->len); 248 free(evp->buf); 249 free(evp); 250 if (tree_empty(&msg->envelopes)) { 251 tree_xpop(&messages, evpid_to_msgid(evpid)); 252 stat_decrement("queue.ram.message.size", msg->len); 253 free(msg->buf); 254 free(msg); 255 } 256 return (1); 257 } 258 259 static int 260 queue_ram_envelope_update(uint64_t evpid, const char *buf, size_t len) 261 { 262 struct qr_envelope *evp; 263 struct qr_message *msg; 264 void *tmp; 265 266 if ((msg = get_message(evpid_to_msgid(evpid))) == NULL) 267 return (0); 268 269 if ((evp = tree_get(&msg->envelopes, evpid)) == NULL) { 270 log_warn("warn: queue-ram: not found"); 271 return (0); 272 } 273 tmp = malloc(len); 274 if (tmp == NULL) { 275 log_warn("warn: queue-ram: malloc"); 276 return (0); 277 } 278 memmove(tmp, buf, len); 279 free(evp->buf); 280 evp->len = len; 281 evp->buf = tmp; 282 stat_decrement("queue.ram.envelope.size", evp->len); 283 stat_increment("queue.ram.envelope.size", len); 284 return (1); 285 } 286 287 static int 288 queue_ram_envelope_load(uint64_t evpid, char *buf, size_t len) 289 { 290 struct qr_envelope *evp; 291 struct qr_message *msg; 292 293 if ((msg = get_message(evpid_to_msgid(evpid))) == NULL) 294 return (0); 295 296 if ((evp = tree_get(&msg->envelopes, evpid)) == NULL) { 297 log_warn("warn: queue-ram: not found"); 298 return (0); 299 } 300 if (len < evp->len) { 301 log_warnx("warn: queue-ram: buffer too small"); 302 return (0); 303 } 304 memmove(buf, evp->buf, evp->len); 305 return (evp->len); 306 } 307 308 static int 309 queue_ram_envelope_walk(uint64_t *evpid, char *buf, size_t len) 310 { 311 return (-1); 312 } 313 314 static int 315 queue_ram_init(struct passwd *pw, int server, const char * conf) 316 { 317 tree_init(&messages); 318 319 queue_api_on_message_create(queue_ram_message_create); 320 queue_api_on_message_commit(queue_ram_message_commit); 321 queue_api_on_message_delete(queue_ram_message_delete); 322 queue_api_on_message_fd_r(queue_ram_message_fd_r); 323 queue_api_on_envelope_create(queue_ram_envelope_create); 324 queue_api_on_envelope_delete(queue_ram_envelope_delete); 325 queue_api_on_envelope_update(queue_ram_envelope_update); 326 queue_api_on_envelope_load(queue_ram_envelope_load); 327 queue_api_on_envelope_walk(queue_ram_envelope_walk); 328 329 return (1); 330 } 331 332 struct queue_backend queue_backend_ram = { 333 queue_ram_init, 334 }; 335