xref: /openbsd/usr.sbin/smtpd/queue_ram.c (revision 8529ddd3)
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