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