xref: /openbsd-src/usr.sbin/smtpd/queue_backend.c (revision 4c1e55dc91edd6e69ccc60ce855900fbc12cf34f)
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