1 /* $OpenBSD: queue_backend.c,v 1.28 2012/07/10 23:21:34 chl Exp $ */ 2 3 /* 4 * Copyright (c) 2011 Gilles Chehade <gilles@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/param.h> 23 #include <sys/socket.h> 24 #include <sys/stat.h> 25 26 #include <ctype.h> 27 #include <event.h> 28 #include <fcntl.h> 29 #include <imsg.h> 30 #include <inttypes.h> 31 #include <libgen.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 39 #include "smtpd.h" 40 #include "log.h" 41 42 static const char* envelope_validate(struct envelope *, uint64_t); 43 44 extern struct queue_backend queue_backend_fs; 45 46 int 47 queue_message_incoming_path(u_int32_t msgid, char *buf, size_t len) 48 { 49 return bsnprintf(buf, len, "%s/%08x", 50 PATH_INCOMING, 51 msgid); 52 } 53 54 int 55 queue_envelope_incoming_path(u_int64_t evpid, char *buf, size_t len) 56 { 57 return bsnprintf(buf, len, "%s/%08x%s/%016" PRIx64, 58 PATH_INCOMING, 59 evpid_to_msgid(evpid), 60 PATH_ENVELOPES, 61 evpid); 62 } 63 64 int 65 queue_message_incoming_delete(u_int32_t msgid) 66 { 67 char rootdir[MAXPATHLEN]; 68 69 if (! queue_message_incoming_path(msgid, rootdir, sizeof(rootdir))) 70 fatal("queue_message_incoming_delete: snprintf"); 71 72 if (rmtree(rootdir, 0) == -1) 73 fatal("queue_message_incoming_delete: rmtree"); 74 75 return 1; 76 } 77 78 struct queue_backend * 79 queue_backend_lookup(const char *name) 80 { 81 if (!strcmp(name, "fs")) 82 return &queue_backend_fs; 83 84 return (NULL); 85 } 86 87 int 88 queue_message_create(u_int32_t *msgid) 89 { 90 return env->sc_queue->message(QOP_CREATE, msgid); 91 } 92 93 int 94 queue_message_delete(u_int32_t msgid) 95 { 96 return env->sc_queue->message(QOP_DELETE, &msgid); 97 } 98 99 int 100 queue_message_commit(u_int32_t msgid) 101 { 102 return env->sc_queue->message(QOP_COMMIT, &msgid); 103 } 104 105 int 106 queue_message_corrupt(u_int32_t msgid) 107 { 108 return env->sc_queue->message(QOP_CORRUPT, &msgid); 109 } 110 111 int 112 queue_message_fd_r(u_int32_t msgid) 113 { 114 return env->sc_queue->message(QOP_FD_R, &msgid); 115 } 116 117 int 118 queue_message_fd_rw(u_int32_t msgid) 119 { 120 char msgpath[MAXPATHLEN]; 121 122 queue_message_incoming_path(msgid, msgpath, sizeof msgpath); 123 strlcat(msgpath, PATH_MESSAGE, sizeof(msgpath)); 124 125 return open(msgpath, O_RDWR | O_CREAT | O_EXCL, 0600); 126 } 127 128 int 129 queue_envelope_create(struct envelope *ep) 130 { 131 int r; 132 133 ep->creation = time(NULL); 134 r = env->sc_queue->envelope(QOP_CREATE, ep); 135 if (!r) { 136 ep->creation = 0; 137 ep->id = 0; 138 } 139 return (r); 140 } 141 142 int 143 queue_envelope_delete(struct envelope *ep) 144 { 145 return env->sc_queue->envelope(QOP_DELETE, ep); 146 } 147 148 int 149 queue_envelope_load(u_int64_t evpid, struct envelope *ep) 150 { 151 const char *e; 152 153 ep->id = evpid; 154 if (env->sc_queue->envelope(QOP_LOAD, ep)) { 155 if ((e = envelope_validate(ep, evpid)) == NULL) { 156 ep->id = evpid; 157 return (1); 158 } 159 log_debug("invalid envelope %016" PRIx64 ": %s", ep->id, e); 160 } 161 return (0); 162 } 163 164 int 165 queue_envelope_update(struct envelope *ep) 166 { 167 return env->sc_queue->envelope(QOP_UPDATE, ep); 168 } 169 170 void * 171 qwalk_new(u_int32_t msgid) 172 { 173 return env->sc_queue->qwalk_new(msgid); 174 } 175 176 int 177 qwalk(void *hdl, u_int64_t *evpid) 178 { 179 return env->sc_queue->qwalk(hdl, evpid); 180 } 181 182 void 183 qwalk_close(void *hdl) 184 { 185 return env->sc_queue->qwalk_close(hdl); 186 } 187 188 u_int32_t 189 queue_generate_msgid(void) 190 { 191 u_int32_t msgid; 192 193 while((msgid = arc4random_uniform(0xffffffff)) == 0) 194 ; 195 196 return msgid; 197 } 198 199 u_int64_t 200 queue_generate_evpid(u_int32_t msgid) 201 { 202 u_int32_t rnd; 203 u_int64_t evpid; 204 205 while((rnd = arc4random_uniform(0xffffffff)) == 0) 206 ; 207 208 evpid = msgid; 209 evpid <<= 32; 210 evpid |= rnd; 211 212 return evpid; 213 } 214 215 216 /**/ 217 static const char* 218 envelope_validate(struct envelope *ep, uint64_t id) 219 { 220 if (ep->version != SMTPD_ENVELOPE_VERSION) 221 return "version mismatch"; 222 223 if (evpid_to_msgid(ep->id) != (evpid_to_msgid(id))) 224 return "msgid mismatch"; 225 226 if (memchr(ep->helo, '\0', sizeof(ep->helo)) == NULL) 227 return "invalid helo"; 228 if (ep->helo[0] == '\0') 229 return "empty helo"; 230 231 if (memchr(ep->hostname, '\0', sizeof(ep->hostname)) == NULL) 232 return "invalid hostname"; 233 if (ep->hostname[0] == '\0') 234 return "empty hostname"; 235 236 if (memchr(ep->errorline, '\0', sizeof(ep->errorline)) == NULL) 237 return "invalid error line"; 238 239 return NULL; 240 } 241