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