xref: /openbsd-src/usr.sbin/smtpd/envelope.c (revision 4c1e55dc91edd6e69ccc60ce855900fbc12cf34f)
1 /*	$OpenBSD: envelope.c,v 1.6 2012/06/03 19:52:56 eric 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 <netinet/in.h>
27 #include <arpa/inet.h>
28 
29 #include <ctype.h>
30 #include <err.h>
31 #include <errno.h>
32 #include <event.h>
33 #include <fcntl.h>
34 #include <imsg.h>
35 #include <inttypes.h>
36 #include <libgen.h>
37 #include <pwd.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <time.h>
42 #include <unistd.h>
43 
44 #include "smtpd.h"
45 #include "log.h"
46 
47 static int ascii_load_uint8(u_int8_t *, char *);
48 static int ascii_load_uint16(u_int16_t *, char *);
49 static int ascii_load_uint32(u_int32_t *, char *);
50 static int ascii_load_time(time_t *, char *);
51 static int ascii_load_uint32_hex(u_int32_t *, char *);
52 static int ascii_load_uint64_hex(u_int64_t *, char *);
53 static int ascii_load_type(enum delivery_type *, char *);
54 static int ascii_load_string(char *, char *, size_t);
55 static int ascii_load_sockaddr(struct sockaddr_storage *, char *);
56 static int ascii_load_mda_method(enum action_type *, char *);
57 static int ascii_load_mailaddr(struct mailaddr *, char *);
58 static int ascii_load_flags(enum delivery_flags *, char *);
59 static int ascii_load_mta_relay_flags(u_int8_t *, char *);
60 
61 static int ascii_dump_uint8(u_int8_t, char *, size_t);
62 static int ascii_dump_uint32(u_int32_t, char *, size_t);
63 static int ascii_dump_time(time_t, char *, size_t);
64 static int ascii_dump_uint32_hex(u_int32_t, char *, size_t);
65 static int ascii_dump_uint64_hex(u_int64_t, char *, size_t);
66 static int ascii_dump_string(char *, char *, size_t);
67 static int ascii_dump_type(enum delivery_type, char *, size_t);
68 static int ascii_dump_mda_method(enum action_type, char *, size_t);
69 static int ascii_dump_mailaddr(struct mailaddr *, char *, size_t);
70 static int ascii_dump_flags(enum delivery_flags, char *, size_t);
71 static int ascii_dump_mta_relay_port(u_int16_t, char *, size_t);
72 static int ascii_dump_mta_relay_flags(u_int8_t, char *, size_t);
73 
74 void
75 envelope_set_errormsg(struct envelope *e, char *fmt, ...)
76 {
77 	int ret;
78 	va_list ap;
79 
80 	va_start(ap, fmt);
81 	ret = vsnprintf(e->errorline, sizeof(e->errorline), fmt, ap);
82 	va_end(ap);
83 
84 	/* this should not happen */
85 	if (ret == -1)
86 		err(1, "vsnprintf");
87 
88 	if ((size_t)ret >= sizeof(e->errorline))
89 		strlcpy(e->errorline + (sizeof(e->errorline) - 4), "...", 4);
90 }
91 
92 int
93 envelope_load_file(struct envelope *ep, FILE *fp)
94 {
95 	char *buf, *lbuf;
96 	char *field;
97 	size_t	len;
98 	enum envelope_field fields[] = {
99 		EVP_VERSION,
100 		EVP_ID,
101 		EVP_MSGID,
102 		EVP_HOSTNAME,
103 		EVP_SOCKADDR,
104 		EVP_HELO,
105 		EVP_SENDER,
106 		EVP_RCPT,
107 		EVP_DEST,
108 		EVP_TYPE,
109 		EVP_CTIME,
110 		EVP_EXPIRE,
111 		EVP_RETRY,
112 		EVP_LASTTRY,
113 		EVP_FLAGS,
114 		EVP_ERRORLINE,
115 		EVP_MDA_METHOD,
116 		EVP_MDA_BUFFER,
117 		EVP_MDA_USER,
118 		EVP_MTA_RELAY_HOST,
119 		EVP_MTA_RELAY_PORT,
120 		EVP_MTA_RELAY_CERT,
121 		EVP_MTA_RELAY_FLAGS,
122 		EVP_MTA_RELAY_AUTHMAP
123 	};
124 	int	i;
125 	int	n;
126 	int	ret;
127 
128 	n = sizeof(fields) / sizeof(enum envelope_field);
129 	bzero(ep, sizeof (*ep));
130 	lbuf = NULL;
131 	while ((buf = fgetln(fp, &len))) {
132 		if (buf[len - 1] == '\n')
133 			buf[len - 1] = '\0';
134 		else {
135 			if ((lbuf = malloc(len + 1)) == NULL)
136 				err(1, NULL);
137 			memcpy(lbuf, buf, len);
138 			lbuf[len] = '\0';
139 			buf = lbuf;
140 		}
141 
142 		for (i = 0; i < n; ++i) {
143 			field = envelope_ascii_field_name(fields[i]);
144 			len = strlen(field);
145 			if (! strncasecmp(field, buf, len)) {
146 				/* skip kw and tailing whitespaces */
147 				buf += len;
148 				while (*buf && isspace(*buf))
149 					buf++;
150 
151 				/* we *want* ':' */
152 				if (*buf != ':')
153 					continue;
154 				buf++;
155 
156 				/* skip whitespaces after separator */
157 				while (*buf && isspace(*buf))
158 				    buf++;
159 
160 				ret = envelope_ascii_load(fields[i], ep, buf);
161 				if (ret == 0)
162 					goto err;
163 				break;
164 			}
165 		}
166 
167 		/* unknown keyword */
168 		if (i == n)
169 			goto err;
170 	}
171 	free(lbuf);
172 	return 1;
173 
174 err:
175 	free(lbuf);
176 	return 0;
177 }
178 
179 int
180 envelope_dump_file(struct envelope *ep, FILE *fp)
181 {
182 	char	buf[8192];
183 
184 	enum envelope_field fields[] = {
185 		EVP_VERSION,
186 		EVP_MSGID,
187 		EVP_TYPE,
188 		EVP_HELO,
189 		EVP_HOSTNAME,
190 		EVP_ERRORLINE,
191 		EVP_SOCKADDR,
192 		EVP_SENDER,
193 		EVP_RCPT,
194 		EVP_DEST,
195 		EVP_CTIME,
196 		EVP_LASTTRY,
197 		EVP_EXPIRE,
198 		EVP_RETRY,
199 		EVP_FLAGS
200 	};
201 	enum envelope_field mda_fields[] = {
202 		EVP_MDA_METHOD,
203 		EVP_MDA_BUFFER,
204 		EVP_MDA_USER
205 	};
206 	enum envelope_field mta_fields[] = {
207 		EVP_MTA_RELAY_HOST,
208 		EVP_MTA_RELAY_PORT,
209 		EVP_MTA_RELAY_CERT,
210 		EVP_MTA_RELAY_AUTHMAP,
211 		EVP_MTA_RELAY_FLAGS
212 	};
213 	enum envelope_field *pfields = NULL;
214 	int	i;
215 	int	n;
216 
217 	n = sizeof(fields) / sizeof(enum envelope_field);
218 	for (i = 0; i < n; ++i) {
219 		bzero(buf, sizeof buf);
220 		if (! envelope_ascii_dump(fields[i], ep, buf, sizeof buf))
221 			goto err;
222 		if (buf[0] == '\0')
223 			continue;
224 		fprintf(fp, "%s: %s\n",
225 		    envelope_ascii_field_name(fields[i]), buf);
226 	}
227 
228 	switch (ep->type) {
229 	case D_MDA:
230 		pfields = mda_fields;
231 		n = sizeof(mda_fields) / sizeof(enum envelope_field);
232 		break;
233 	case D_MTA:
234 		pfields = mta_fields;
235 		n = sizeof(mta_fields) / sizeof(enum envelope_field);
236 		break;
237 	case D_BOUNCE:
238 		/* nothing ! */
239 		break;
240 	default:
241 		goto err;
242 	}
243 
244 	if (pfields) {
245 		for (i = 0; i < n; ++i) {
246 			bzero(buf, sizeof buf);
247 			if (! envelope_ascii_dump(pfields[i], ep, buf,
248 				sizeof buf))
249 				goto err;
250 			if (buf[0] == '\0')
251 				continue;
252 			fprintf(fp, "%s: %s\n",
253 			    envelope_ascii_field_name(pfields[i]), buf);
254 		}
255 	}
256 
257 	if (fflush(fp) != 0)
258 		goto err;
259 
260 	return 1;
261 
262 err:
263 	return 0;
264 }
265 
266 char *
267 envelope_ascii_field_name(enum envelope_field field)
268 {
269 	switch (field) {
270 	case EVP_VERSION:
271 		return "version";
272 	case EVP_ID:
273 		return "id";
274 	case EVP_MSGID:
275 		return "msgid";
276 	case EVP_TYPE:
277 		return "type";
278 	case EVP_HELO:
279 		return "helo";
280 	case EVP_HOSTNAME:
281 		return "hostname";
282 	case EVP_ERRORLINE:
283 		return "errorline";
284 	case EVP_SOCKADDR:
285 		return "sockaddr";
286 	case EVP_SENDER:
287 		return "sender";
288 	case EVP_RCPT:
289 		return "rcpt";
290 	case EVP_DEST:
291 		return "dest";
292 	case EVP_CTIME:
293 		return "ctime";
294 	case EVP_EXPIRE:
295 		return "expire";
296 	case EVP_RETRY:
297 		return "retry";
298 	case EVP_LASTTRY:
299 		return "last-try";
300 	case EVP_FLAGS:
301 		return "flags";
302 	case EVP_MDA_METHOD:
303 		return "mda-method";
304 	case EVP_MDA_BUFFER:
305 		return "mda-buffer";
306 	case EVP_MDA_USER:
307 		return "mda-user";
308 	case EVP_MTA_RELAY_HOST:
309 		return "mta-relay-host";
310 	case EVP_MTA_RELAY_PORT:
311 		return "mta-relay-port";
312 	case EVP_MTA_RELAY_FLAGS:
313 		return "mta-relay-flags";
314 	case EVP_MTA_RELAY_CERT:
315 		return "mta-relay-cert";
316 	case EVP_MTA_RELAY_AUTHMAP:
317 		return "mta-relay-authmap";
318 	}
319 
320 	return NULL;
321 }
322 
323 int
324 envelope_ascii_load(enum envelope_field field, struct envelope *ep, char *buf)
325 {
326 	uint32_t	msgid;
327 	int		r;
328 
329 	switch (field) {
330 	case EVP_VERSION:
331 		return ascii_load_uint32(&ep->version, buf);
332 	case EVP_ID:
333 		return ascii_load_uint64_hex(&ep->id, buf);
334 	case EVP_MSGID:
335 		if ((r = ascii_load_uint32_hex(&msgid, buf)))
336 			ep->id = msgid_to_evpid(msgid);
337 		return (r);
338 	case EVP_TYPE:
339 		return ascii_load_type(&ep->type, buf);
340 	case EVP_HELO:
341 		return ascii_load_string(ep->helo, buf, sizeof ep->helo);
342 	case EVP_HOSTNAME:
343 		return ascii_load_string(ep->hostname, buf,
344 		    sizeof ep->hostname);
345 	case EVP_ERRORLINE:
346 		return ascii_load_string(ep->errorline, buf,
347 		    sizeof ep->errorline);
348 	case EVP_SOCKADDR:
349 		return ascii_load_sockaddr(&ep->ss, buf);
350 	case EVP_SENDER:
351 		return ascii_load_mailaddr(&ep->sender, buf);
352 	case EVP_RCPT:
353 		return ascii_load_mailaddr(&ep->rcpt, buf);
354 	case EVP_DEST:
355 		return ascii_load_mailaddr(&ep->dest, buf);
356 	case EVP_MDA_METHOD:
357 		return ascii_load_mda_method(&ep->agent.mda.method, buf);
358 	case EVP_MDA_BUFFER:
359 		return ascii_load_string(ep->agent.mda.to.buffer, buf,
360 		    sizeof ep->agent.mda.to.buffer);
361 	case EVP_MDA_USER:
362 		return ascii_load_string(ep->agent.mda.as_user, buf,
363 		    sizeof ep->agent.mda.as_user);
364 	case EVP_MTA_RELAY_HOST:
365 		return ascii_load_string(ep->agent.mta.relay.hostname, buf,
366 		    sizeof ep->agent.mta.relay.hostname);
367 	case EVP_MTA_RELAY_PORT: {
368 		u_int16_t port;
369 
370 		if (! ascii_load_uint16(&port, buf))
371 			return 0;
372 		ep->agent.mta.relay.port = htons(port);
373 		return 1;
374 	}
375 	case EVP_MTA_RELAY_CERT:
376 		return ascii_load_string(ep->agent.mta.relay.cert, buf,
377 		    sizeof ep->agent.mta.relay.cert);
378 	case EVP_MTA_RELAY_FLAGS:
379 		return ascii_load_mta_relay_flags(&ep->agent.mta.relay.flags,
380 		    buf);
381 	case EVP_MTA_RELAY_AUTHMAP:
382 		return ascii_load_string(ep->agent.mta.relay.authmap, buf,
383 		    sizeof ep->agent.mta.relay.authmap);
384 	case EVP_CTIME:
385 		return ascii_load_time(&ep->creation, buf);
386 	case EVP_EXPIRE:
387 		return ascii_load_time(&ep->expire, buf);
388 	case EVP_RETRY:
389 		return ascii_load_uint8(&ep->retry, buf);
390 	case EVP_LASTTRY:
391 		return ascii_load_time(&ep->lasttry, buf);
392 	case EVP_FLAGS:
393 		return ascii_load_flags(&ep->flags, buf);
394 	}
395 	return 0;
396 }
397 
398 int
399 envelope_ascii_dump(enum envelope_field field, struct envelope *ep,
400     char *buf, size_t len)
401 {
402 	switch (field) {
403 	case EVP_VERSION:
404 		return ascii_dump_uint32(SMTPD_ENVELOPE_VERSION, buf, len);
405 	case EVP_ID:
406 		return ascii_dump_uint64_hex(ep->id, buf, len);
407 	case EVP_MSGID:
408 		return ascii_dump_uint32_hex(evpid_to_msgid(ep->id), buf, len);
409 	case EVP_TYPE:
410 		return ascii_dump_type(ep->type, buf, len);
411 	case EVP_HELO:
412 		return ascii_dump_string(ep->helo, buf, len);
413 	case EVP_HOSTNAME:
414 		return ascii_dump_string(ep->hostname, buf, len);
415 	case EVP_ERRORLINE:
416 		return ascii_dump_string(ep->errorline, buf, len);
417 	case EVP_SOCKADDR:
418 		return ascii_dump_string(ss_to_text(&ep->ss), buf, len);
419 	case EVP_SENDER:
420 		return ascii_dump_mailaddr(&ep->sender, buf, len);
421 	case EVP_RCPT:
422 		return ascii_dump_mailaddr(&ep->rcpt, buf, len);
423 	case EVP_DEST:
424 		return ascii_dump_mailaddr(&ep->dest, buf, len);
425 	case EVP_MDA_METHOD:
426 		return ascii_dump_mda_method(ep->agent.mda.method, buf, len);
427 	case EVP_MDA_BUFFER:
428 		return ascii_dump_string(ep->agent.mda.to.buffer, buf, len);
429 	case EVP_MDA_USER:
430 		return ascii_dump_string(ep->agent.mda.as_user, buf, len);
431 	case EVP_MTA_RELAY_HOST:
432 		return ascii_dump_string(ep->agent.mta.relay.hostname,
433 		    buf, len);
434 	case EVP_MTA_RELAY_PORT:
435 		return ascii_dump_mta_relay_port(ep->agent.mta.relay.port,
436 		    buf, len);
437 	case EVP_MTA_RELAY_CERT:
438 		return ascii_dump_string(ep->agent.mta.relay.cert,
439 		    buf, len);
440 	case EVP_MTA_RELAY_FLAGS:
441 		return ascii_dump_mta_relay_flags(ep->agent.mta.relay.flags,
442 		    buf, len);
443 	case EVP_MTA_RELAY_AUTHMAP:
444 		return ascii_dump_string(ep->agent.mta.relay.authmap,
445 		    buf, len);
446 	case EVP_CTIME:
447 		return ascii_dump_time(ep->creation, buf, len);
448 	case EVP_EXPIRE:
449 		return ascii_dump_time(ep->expire, buf, len);
450 	case EVP_RETRY:
451 		return ascii_dump_uint8(ep->retry, buf, len);
452 	case EVP_LASTTRY:
453 		return ascii_dump_time(ep->lasttry, buf, len);
454 	case EVP_FLAGS:
455 		return ascii_dump_flags(ep->flags, buf, len);
456 	}
457 	return 0;
458 }
459 
460 static int
461 ascii_load_uint8(u_int8_t *dest, char *buf)
462 {
463 	const char *errstr;
464 
465 	*dest = strtonum(buf, 0, 0xff, &errstr);
466 	if (errstr)
467 		return 0;
468 	return 1;
469 }
470 
471 static int
472 ascii_load_uint16(u_int16_t *dest, char *buf)
473 {
474 	const char *errstr;
475 
476 	*dest = strtonum(buf, 0, 0xffff, &errstr);
477 	if (errstr)
478 		return 0;
479 	return 1;
480 }
481 
482 static int
483 ascii_load_uint32(u_int32_t *dest, char *buf)
484 {
485 	const char *errstr;
486 
487 	*dest = strtonum(buf, 0, 0xffffffff, &errstr);
488 	if (errstr)
489 		return 0;
490 	return 1;
491 }
492 
493 static int
494 ascii_load_time(time_t *dest, char *buf)
495 {
496 	const char *errstr;
497 
498 	*dest = (time_t) strtonum(buf, 0, 0x7fffffff, &errstr);
499 	if (errstr)
500 		return 0;
501 	return 1;
502 }
503 
504 static int
505 ascii_load_uint32_hex(u_int32_t *dest, char *buf)
506 {
507 	uint64_t	u;
508 
509 	if (ascii_load_uint64_hex(&u, buf) == 0)
510 		return (0);
511 	if (u > (uint64_t)0xffffffff)
512 		return (0);
513 	*dest = (uint32_t)u;
514 	return (1);
515 }
516 
517 static int
518 ascii_load_uint64_hex(u_int64_t *dest, char *buf)
519 {
520 	char *endptr;
521 
522 	*dest = strtoull(buf, &endptr, 16);
523 	if (buf[0] == '\0' || *endptr != '\0')
524 		return 0;
525 	if (errno == ERANGE && *dest == ULLONG_MAX)
526 		return 0;
527 	return 1;
528 }
529 
530 static int
531 ascii_load_type(enum delivery_type *dest, char *buf)
532 {
533 	if (strcasecmp(buf, "mda") == 0)
534 		*dest = D_MDA;
535 	else if (strcasecmp(buf, "mta") == 0)
536 		*dest = D_MTA;
537 	else if (strcasecmp(buf, "bounce") == 0)
538 		*dest = D_BOUNCE;
539 	else
540 		return 0;
541 	return 1;
542 }
543 
544 static int
545 ascii_load_string(char *dest, char *buf, size_t len)
546 {
547 	if (strlcpy(dest, buf, len) >= len)
548 		return 0;
549 	return 1;
550 }
551 
552 static int
553 ascii_load_sockaddr(struct sockaddr_storage *ss, char *buf)
554 {
555 	struct sockaddr_in6 ssin6;
556 	struct sockaddr_in  ssin;
557 
558 	if (strncasecmp("IPv6:", buf, 5) == 0) {
559 		if (inet_pton(AF_INET6, buf + 5, &ssin6.sin6_addr) != 1)
560 			return 0;
561 		ssin6.sin6_family = AF_INET6;
562 		memcpy(ss, &ssin6, sizeof(ssin6));
563 		ss->ss_len = sizeof(struct sockaddr_in6);
564 	}
565 	else {
566 		if (inet_pton(AF_INET, buf, &ssin.sin_addr) != 1)
567 			return 0;
568 		ssin.sin_family = AF_INET;
569 		memcpy(ss, &ssin, sizeof(ssin));
570 		ss->ss_len = sizeof(struct sockaddr_in);
571 	}
572 	return 1;
573 }
574 
575 static int
576 ascii_load_mda_method(enum action_type *dest, char *buf)
577 {
578 	if (strcasecmp(buf, "mbox") == 0)
579 		*dest = A_MBOX;
580 	else if (strcasecmp(buf, "maildir") == 0)
581 		*dest = A_MAILDIR;
582 	else if (strcasecmp(buf, "filename") == 0)
583 		*dest = A_FILENAME;
584 	else if (strcasecmp(buf, "mda") == 0)
585 		*dest = A_MDA;
586 	else
587 		return 0;
588 	return 1;
589 }
590 
591 static int
592 ascii_load_mailaddr(struct mailaddr *dest, char *buf)
593 {
594 	if (! email_to_mailaddr(dest, buf))
595 		return 0;
596 	return 1;
597 }
598 
599 static int
600 ascii_load_flags(enum delivery_flags *dest, char *buf)
601 {
602 	char *flag;
603 
604 	while ((flag = strsep(&buf, " ,|")) != NULL) {
605 		if (strcasecmp(flag, "authenticated") == 0)
606 			*dest |= DF_AUTHENTICATED;
607 		else if (strcasecmp(flag, "enqueued") == 0)
608 			*dest |= DF_ENQUEUED;
609 		else if (strcasecmp(flag, "bounce") == 0)
610 			*dest |= DF_BOUNCE;
611 		else if (strcasecmp(flag, "internal") == 0)
612 			*dest |= DF_INTERNAL;
613 		else
614 			return 0;
615 	}
616 	return 1;
617 }
618 
619 static int
620 ascii_load_mta_relay_flags(u_int8_t *dest, char *buf)
621 {
622 	char *flag;
623 
624 	while ((flag = strsep(&buf, " ,|")) != NULL) {
625 		if (strcasecmp(flag, "smtps") == 0)
626 			*dest |= F_SMTPS;
627 		else if (strcasecmp(flag, "tls") == 0)
628 			*dest |= F_STARTTLS;
629 		else if (strcasecmp(flag, "auth") == 0)
630 			*dest |= F_AUTH;
631 		else
632 			return 0;
633 	}
634 	return 1;
635 }
636 
637 static int
638 ascii_dump_uint8(u_int8_t src, char *dest, size_t len)
639 {
640 	return bsnprintf(dest, len, "%d", src);
641 }
642 
643 static int
644 ascii_dump_uint32(u_int32_t src, char *dest, size_t len)
645 {
646 	return bsnprintf(dest, len, "%d", src);
647 }
648 
649 static int
650 ascii_dump_time(time_t src, char *dest, size_t len)
651 {
652 	return bsnprintf(dest, len, "%" PRId64, (int64_t) src);
653 }
654 
655 static int
656 ascii_dump_uint32_hex(u_int32_t src, char *dest, size_t len)
657 {
658 	return bsnprintf(dest, len, "%08" PRIx32, src);
659 }
660 
661 static int
662 ascii_dump_uint64_hex(u_int64_t src, char *dest, size_t len)
663 {
664 	return bsnprintf(dest, len, "%016" PRIx64, src);
665 }
666 
667 static int
668 ascii_dump_string(char *src, char *dest, size_t len)
669 {
670 	return bsnprintf(dest, len, "%s", src);
671 }
672 
673 static int
674 ascii_dump_type(enum delivery_type type, char *dest, size_t len)
675 {
676 	char *p = NULL;
677 
678 	switch (type) {
679 	case D_MDA:
680 		p = "mda";
681 		break;
682 	case D_MTA:
683 		p = "mta";
684 		break;
685 	case D_BOUNCE:
686 		p = "bounce";
687 		break;
688 	default:
689 		return 0;
690 	}
691 
692 	return bsnprintf(dest, len, "%s", p);
693 }
694 
695 static int
696 ascii_dump_mda_method(enum action_type type, char *dest, size_t len)
697 {
698 	char *p = NULL;
699 
700 	switch (type) {
701 	case A_MAILDIR:
702 		p = "maildir";
703 		break;
704 	case A_MBOX:
705 		p = "mbox";
706 		break;
707 	case A_FILENAME:
708 		p = "filename";
709 		break;
710 	case A_MDA:
711 		p = "mda";
712 		break;
713 	default:
714 		return 0;
715 	}
716 	return bsnprintf(dest, len, "%s", p);
717 }
718 
719 static int
720 ascii_dump_mailaddr(struct mailaddr *addr, char *dest, size_t len)
721 {
722 	return bsnprintf(dest, len, "%s@%s",
723 	    addr->user, addr->domain);
724 }
725 
726 static int
727 ascii_dump_mta_relay_port(u_int16_t port, char *buf, size_t len)
728 {
729 	return bsnprintf(buf, len, "%d", ntohs(port));
730 }
731 
732 static int
733 ascii_dump_mta_relay_flags(u_int8_t flags, char *buf, size_t len)
734 {
735 	size_t cpylen = 0;
736 
737 	buf[0] = '\0';
738 	if (flags) {
739 		if (flags & F_SMTPS)
740 			cpylen = strlcat(buf, "smtps", len);
741 		if (flags & F_STARTTLS) {
742 			if (buf[0] != '\0')
743 				cpylen = strlcat(buf, " ", len);
744 			cpylen = strlcat(buf, "tls", len);
745 		}
746 		if (flags & F_AUTH) {
747 			if (buf[0] != '\0')
748 				cpylen = strlcat(buf, " ", len);
749 			cpylen = strlcat(buf, "auth", len);
750 		}
751 	}
752 
753 	return cpylen < len ? 1 : 0;
754 }
755 
756 static int
757 ascii_dump_flags(enum delivery_flags flags, char *buf, size_t len)
758 {
759 	size_t cpylen = 0;
760 
761 	buf[0] = '\0';
762 	if (flags) {
763 		if (flags & DF_AUTHENTICATED)
764 			cpylen = strlcat(buf, "authenticated", len);
765 		if (flags & DF_ENQUEUED) {
766 			if (buf[0] != '\0')
767 				cpylen = strlcat(buf, " ", len);
768 			cpylen = strlcat(buf, "enqueued", len);
769 		}
770 		if (flags & DF_BOUNCE) {
771 			if (buf[0] != '\0')
772 				cpylen = strlcat(buf, " ", len);
773 			cpylen = strlcat(buf, "bounce", len);
774 		}
775 		if (flags & DF_INTERNAL) {
776 			if (buf[0] != '\0')
777 				cpylen = strlcat(buf, " ", len);
778 			cpylen = strlcat(buf, "internal", len);
779 		}
780 	}
781 
782 	return cpylen < len ? 1 : 0;
783 }
784