xref: /openbsd-src/usr.sbin/smtpd/queue_backend.c (revision 8dbeaf78030d859397626dfdd31ea369b51e268f)
1*8dbeaf78Seric /*	$OpenBSD: queue_backend.c,v 1.21 2012/06/01 11:42:34 eric Exp $	*/
22a81c1f8Sgilles 
32a81c1f8Sgilles /*
42a81c1f8Sgilles  * Copyright (c) 2011 Gilles Chehade <gilles@openbsd.org>
52a81c1f8Sgilles  *
62a81c1f8Sgilles  * Permission to use, copy, modify, and distribute this software for any
72a81c1f8Sgilles  * purpose with or without fee is hereby granted, provided that the above
82a81c1f8Sgilles  * copyright notice and this permission notice appear in all copies.
92a81c1f8Sgilles  *
102a81c1f8Sgilles  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
112a81c1f8Sgilles  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
122a81c1f8Sgilles  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
132a81c1f8Sgilles  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
142a81c1f8Sgilles  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
152a81c1f8Sgilles  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
162a81c1f8Sgilles  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
172a81c1f8Sgilles  */
182a81c1f8Sgilles 
192a81c1f8Sgilles #include <sys/types.h>
202a81c1f8Sgilles #include <sys/queue.h>
212a81c1f8Sgilles #include <sys/tree.h>
222a81c1f8Sgilles #include <sys/param.h>
232a81c1f8Sgilles #include <sys/socket.h>
242a81c1f8Sgilles #include <sys/stat.h>
252a81c1f8Sgilles 
26148c5951Sgilles #include <ctype.h>
272a81c1f8Sgilles #include <event.h>
282a81c1f8Sgilles #include <imsg.h>
29b5c4b6b5Schl #include <inttypes.h>
302a81c1f8Sgilles #include <libgen.h>
312a81c1f8Sgilles #include <pwd.h>
322a81c1f8Sgilles #include <stdio.h>
332a81c1f8Sgilles #include <stdlib.h>
342a81c1f8Sgilles #include <string.h>
352a81c1f8Sgilles #include <unistd.h>
362a81c1f8Sgilles 
372a81c1f8Sgilles #include "smtpd.h"
382a81c1f8Sgilles #include "log.h"
392a81c1f8Sgilles 
40d97aaa5bSeric static const char* envelope_validate(struct envelope *, uint64_t);
41148c5951Sgilles 
423f522ce8Sgilles /* fsqueue backend */
43c91bb5c0Seric extern struct queue_backend	queue_backend_fs;
447b5d776dSgilles 
452a81c1f8Sgilles 
462a81c1f8Sgilles struct queue_backend *
472a81c1f8Sgilles queue_backend_lookup(enum queue_type type)
482a81c1f8Sgilles {
49c91bb5c0Seric 	switch (type) {
50c91bb5c0Seric 	case QT_FS:
51c91bb5c0Seric 		return &queue_backend_fs;
522a81c1f8Sgilles 
53c91bb5c0Seric 	default:
542a81c1f8Sgilles 		fatalx("invalid queue type");
55c91bb5c0Seric 	}
562a81c1f8Sgilles 
57c91bb5c0Seric 	return (NULL);
582a81c1f8Sgilles }
592a81c1f8Sgilles 
602a81c1f8Sgilles int
61e4d36f12Seric queue_message_create(enum queue_kind qkind, u_int32_t *msgid)
622a81c1f8Sgilles {
63e4d36f12Seric 	return env->sc_queue->message(qkind, QOP_CREATE, msgid);
642a81c1f8Sgilles }
652a81c1f8Sgilles 
662a81c1f8Sgilles int
67e4d36f12Seric queue_message_delete(enum queue_kind qkind, u_int32_t msgid)
682a81c1f8Sgilles {
69e4d36f12Seric 	return env->sc_queue->message(qkind, QOP_DELETE, &msgid);
702a81c1f8Sgilles }
712a81c1f8Sgilles 
722a81c1f8Sgilles int
73e4d36f12Seric queue_message_commit(enum queue_kind qkind, u_int32_t msgid)
742a81c1f8Sgilles {
75e4d36f12Seric 	return env->sc_queue->message(qkind, QOP_COMMIT, &msgid);
762a81c1f8Sgilles }
772a81c1f8Sgilles 
782a81c1f8Sgilles int
79b31e1002Sgilles queue_message_corrupt(enum queue_kind qkind, u_int32_t msgid)
80b31e1002Sgilles {
81b31e1002Sgilles 	return env->sc_queue->message(qkind, QOP_CORRUPT, &msgid);
82b31e1002Sgilles }
83b31e1002Sgilles 
84b31e1002Sgilles int
85e4d36f12Seric queue_message_fd_r(enum queue_kind qkind, u_int32_t msgid)
862a81c1f8Sgilles {
87e4d36f12Seric 	return env->sc_queue->message(qkind, QOP_FD_R, &msgid);
882a81c1f8Sgilles }
892a81c1f8Sgilles 
902a81c1f8Sgilles int
91e4d36f12Seric queue_message_fd_rw(enum queue_kind qkind, u_int32_t msgid)
922a81c1f8Sgilles {
93e4d36f12Seric 	return env->sc_queue->message(qkind, QOP_FD_RW, &msgid);
942a81c1f8Sgilles }
952a81c1f8Sgilles 
962a81c1f8Sgilles int
975ff81a3dSgilles queue_envelope_create(enum queue_kind qkind, struct envelope *ep)
982a81c1f8Sgilles {
99*8dbeaf78Seric 	int r;
100*8dbeaf78Seric 
101*8dbeaf78Seric 	ep->creation = time(NULL);
102*8dbeaf78Seric 	r = env->sc_queue->envelope(qkind, QOP_CREATE, ep);
103*8dbeaf78Seric 	if (!r) {
104*8dbeaf78Seric 		ep->creation = 0;
105*8dbeaf78Seric 		ep->id = 0;
106*8dbeaf78Seric 	}
107*8dbeaf78Seric 	return (r);
1082a81c1f8Sgilles }
1092a81c1f8Sgilles 
1102a81c1f8Sgilles int
1115ff81a3dSgilles queue_envelope_delete(enum queue_kind qkind, struct envelope *ep)
1122a81c1f8Sgilles {
1135ff81a3dSgilles 	return env->sc_queue->envelope(qkind, QOP_DELETE, ep);
1142a81c1f8Sgilles }
1152a81c1f8Sgilles 
1162a81c1f8Sgilles int
1175ff81a3dSgilles queue_envelope_load(enum queue_kind qkind, u_int64_t evpid, struct envelope *ep)
1182a81c1f8Sgilles {
119d97aaa5bSeric 	const char	*e;
120d97aaa5bSeric 
121148c5951Sgilles 	ep->id = evpid;
122d97aaa5bSeric 	if (env->sc_queue->envelope(qkind, QOP_LOAD, ep)) {
123d97aaa5bSeric 		if ((e = envelope_validate(ep, evpid)) == NULL)
124d97aaa5bSeric 			return 1;
125d97aaa5bSeric 		log_debug("invalid envelope %016" PRIx64 ": %s", ep->id, e);
126d97aaa5bSeric 	}
127148c5951Sgilles 	return 0;
1282a81c1f8Sgilles }
1292a81c1f8Sgilles 
1302a81c1f8Sgilles int
1315ff81a3dSgilles queue_envelope_update(enum queue_kind qkind, struct envelope *ep)
1322a81c1f8Sgilles {
1335ff81a3dSgilles 	return env->sc_queue->envelope(qkind, QOP_UPDATE, ep);
1342a81c1f8Sgilles }
135148c5951Sgilles 
1367b5d776dSgilles void *
1377b5d776dSgilles qwalk_new(enum queue_kind kind, u_int32_t msgid)
1387b5d776dSgilles {
1397b5d776dSgilles 	return env->sc_queue->qwalk_new(kind, msgid);
1407b5d776dSgilles }
1417b5d776dSgilles 
1427b5d776dSgilles int
1437b5d776dSgilles qwalk(void *hdl, u_int64_t *evpid)
1447b5d776dSgilles {
1457b5d776dSgilles 	return env->sc_queue->qwalk(hdl, evpid);
1467b5d776dSgilles }
1477b5d776dSgilles 
1487b5d776dSgilles void
1497b5d776dSgilles qwalk_close(void *hdl)
1507b5d776dSgilles {
1517b5d776dSgilles 	return env->sc_queue->qwalk_close(hdl);
1527b5d776dSgilles }
1537b5d776dSgilles 
1547b5d776dSgilles u_int32_t
1557b5d776dSgilles queue_generate_msgid(void)
1567b5d776dSgilles {
1577b5d776dSgilles 	u_int32_t msgid;
1587b5d776dSgilles 
1599f0761fdSeric 	while((msgid = arc4random_uniform(0xffffffff)) == 0)
1609f0761fdSeric 		;
1617b5d776dSgilles 
1627b5d776dSgilles 	return msgid;
1637b5d776dSgilles }
1647b5d776dSgilles 
1657b5d776dSgilles u_int64_t
1667b5d776dSgilles queue_generate_evpid(u_int32_t msgid)
1677b5d776dSgilles {
1687b5d776dSgilles 	u_int32_t rnd;
1697b5d776dSgilles 	u_int64_t evpid;
1707b5d776dSgilles 
1719f0761fdSeric 	while((rnd = arc4random_uniform(0xffffffff)) == 0)
1729f0761fdSeric 		;
1737b5d776dSgilles 
1747b5d776dSgilles 	evpid = msgid;
1757b5d776dSgilles 	evpid <<= 32;
1767b5d776dSgilles 	evpid |= rnd;
1777b5d776dSgilles 
1787b5d776dSgilles 	return evpid;
1797b5d776dSgilles }
1807b5d776dSgilles 
1817b5d776dSgilles 
1827b5d776dSgilles /**/
183d97aaa5bSeric static const char*
184d97aaa5bSeric envelope_validate(struct envelope *ep, uint64_t id)
185148c5951Sgilles {
186148c5951Sgilles 	if (ep->version != SMTPD_ENVELOPE_VERSION)
187d97aaa5bSeric 		return "version mismatch";
188148c5951Sgilles 
189d97aaa5bSeric 	if ((ep->id & 0xffffffff) == 0 || ((ep->id >> 32) & 0xffffffff) == 0)
190d97aaa5bSeric 		return "invalid id";
191148c5951Sgilles 
192d97aaa5bSeric 	if (ep->id != id)
193d97aaa5bSeric 		return "id mismatch";
194d97aaa5bSeric 
195d97aaa5bSeric 	if (memchr(ep->helo, '\0', sizeof(ep->helo)) == NULL)
196d97aaa5bSeric 		return "invalid helo";
197148c5951Sgilles 	if (ep->helo[0] == '\0')
198d97aaa5bSeric 		return "empty helo";
199148c5951Sgilles 
200d97aaa5bSeric 	if (memchr(ep->hostname, '\0', sizeof(ep->hostname)) == NULL)
201d97aaa5bSeric 		return "invalid hostname";
202148c5951Sgilles 	if (ep->hostname[0] == '\0')
203d97aaa5bSeric 		return "empty hostname";
204148c5951Sgilles 
205d97aaa5bSeric 	if (memchr(ep->errorline, '\0', sizeof(ep->errorline)) == NULL)
206d97aaa5bSeric 		return "invalid error line";
207148c5951Sgilles 
208d97aaa5bSeric 	return NULL;
209148c5951Sgilles }
210