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