1 /* $OpenBSD: queue_ram.c,v 1.8 2018/05/14 15:23:05 gilles 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_envelope_create(uint32_t msgid, const char *buf, size_t len, 206 uint64_t *evpid) 207 { 208 struct qr_envelope *evp; 209 struct qr_message *msg; 210 211 if ((msg = get_message(msgid)) == NULL) 212 return (0); 213 214 do { 215 *evpid = queue_generate_evpid(msgid); 216 } while (tree_check(&msg->envelopes, *evpid)); 217 evp = calloc(1, sizeof *evp); 218 if (evp == NULL) { 219 log_warn("warn: queue-ram: calloc"); 220 return (0); 221 } 222 evp->len = len; 223 evp->buf = malloc(len); 224 if (evp->buf == NULL) { 225 log_warn("warn: queue-ram: malloc"); 226 free(evp); 227 return (0); 228 } 229 memmove(evp->buf, buf, len); 230 tree_xset(&msg->envelopes, *evpid, evp); 231 stat_increment("queue.ram.envelope.size", len); 232 return (1); 233 } 234 235 static int 236 queue_ram_envelope_delete(uint64_t evpid) 237 { 238 struct qr_envelope *evp; 239 struct qr_message *msg; 240 241 if ((msg = get_message(evpid_to_msgid(evpid))) == NULL) 242 return (0); 243 244 if ((evp = tree_pop(&msg->envelopes, evpid)) == NULL) { 245 log_warnx("warn: queue-ram: not found"); 246 return (0); 247 } 248 stat_decrement("queue.ram.envelope.size", evp->len); 249 free(evp->buf); 250 free(evp); 251 if (tree_empty(&msg->envelopes)) { 252 tree_xpop(&messages, evpid_to_msgid(evpid)); 253 stat_decrement("queue.ram.message.size", msg->len); 254 free(msg->buf); 255 free(msg); 256 } 257 return (1); 258 } 259 260 static int 261 queue_ram_envelope_update(uint64_t evpid, const char *buf, size_t len) 262 { 263 struct qr_envelope *evp; 264 struct qr_message *msg; 265 void *tmp; 266 267 if ((msg = get_message(evpid_to_msgid(evpid))) == NULL) 268 return (0); 269 270 if ((evp = tree_get(&msg->envelopes, evpid)) == NULL) { 271 log_warn("warn: queue-ram: not found"); 272 return (0); 273 } 274 tmp = malloc(len); 275 if (tmp == NULL) { 276 log_warn("warn: queue-ram: malloc"); 277 return (0); 278 } 279 memmove(tmp, buf, len); 280 free(evp->buf); 281 evp->len = len; 282 evp->buf = tmp; 283 stat_decrement("queue.ram.envelope.size", evp->len); 284 stat_increment("queue.ram.envelope.size", len); 285 return (1); 286 } 287 288 static int 289 queue_ram_envelope_load(uint64_t evpid, char *buf, size_t len) 290 { 291 struct qr_envelope *evp; 292 struct qr_message *msg; 293 294 if ((msg = get_message(evpid_to_msgid(evpid))) == NULL) 295 return (0); 296 297 if ((evp = tree_get(&msg->envelopes, evpid)) == NULL) { 298 log_warn("warn: queue-ram: not found"); 299 return (0); 300 } 301 if (len < evp->len) { 302 log_warnx("warn: queue-ram: buffer too small"); 303 return (0); 304 } 305 memmove(buf, evp->buf, evp->len); 306 return (evp->len); 307 } 308 309 static int 310 queue_ram_envelope_walk(uint64_t *evpid, char *buf, size_t len) 311 { 312 return (-1); 313 } 314 315 static int 316 queue_ram_init(struct passwd *pw, int server, const char * conf) 317 { 318 tree_init(&messages); 319 320 queue_api_on_message_create(queue_ram_message_create); 321 queue_api_on_message_commit(queue_ram_message_commit); 322 queue_api_on_message_delete(queue_ram_message_delete); 323 queue_api_on_message_fd_r(queue_ram_message_fd_r); 324 queue_api_on_envelope_create(queue_ram_envelope_create); 325 queue_api_on_envelope_delete(queue_ram_envelope_delete); 326 queue_api_on_envelope_update(queue_ram_envelope_update); 327 queue_api_on_envelope_load(queue_ram_envelope_load); 328 queue_api_on_envelope_walk(queue_ram_envelope_walk); 329 330 return (1); 331 } 332 333 struct queue_backend queue_backend_ram = { 334 queue_ram_init, 335 }; 336