GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/smtpd/smtpd/../delivery_lmtp.c Lines: 0 110 0.0 %
Date: 2017-11-13 Branches: 0 86 0.0 %

Line Branch Exec Source
1
/* $OpenBSD: delivery_lmtp.c,v 1.17 2016/06/05 12:10:28 gilles Exp $ */
2
3
/*
4
 * Copyright (c) 2013 Ashish SHUKLA <ashish.is@lostca.se>
5
 * Copyright (c) 2015 Sunil Nimmagadda <sunil@nimmagadda.net>
6
 *
7
 * Permission to use, copy, modify, and distribute this software for any
8
 * purpose with or without fee is hereby granted, provided that the above
9
 * copyright notice and this permission notice appear in all copies.
10
 *
11
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
 */
19
20
#include <sys/socket.h>
21
#include <sys/tree.h>
22
#include <sys/un.h>
23
24
#include <ctype.h>
25
#include <err.h>
26
#include <errno.h>
27
#include <event.h>
28
#include <fcntl.h>
29
#include <imsg.h>
30
#include <limits.h>
31
#include <netdb.h>
32
#include <stdio.h>
33
#include <stdlib.h>
34
#include <string.h>
35
#include <unistd.h>
36
37
#include "smtpd.h"
38
39
/* should be more than enough for any LMTP server */
40
#define	MAX_CONTINUATIONS	100
41
42
static int	inet_socket(char *);
43
static int	lmtp_banner(char **buf, size_t *, int, FILE *);
44
static int	lmtp_cmd(char **buf, size_t *, int, FILE *, const char *, ...)
45
		    __attribute__((__format__ (printf, 5, 6)))
46
		    __attribute__((__nonnull__ (5)));
47
static void	lmtp_open(struct deliver *);
48
static int	unix_socket(char *);
49
50
struct delivery_backend delivery_backend_lmtp = {
51
	 0, lmtp_open
52
};
53
54
static int
55
inet_socket(char *address)
56
{
57
	 struct addrinfo	 hints, *res, *res0;
58
	 char			*hostname, *servname;
59
	 const char		*cause = NULL;
60
	 int			 n, s = -1, save_errno;
61
62
	 if ((servname = strchr(address, ':')) == NULL)
63
		 errx(1, "invalid address: %s", address);
64
65
	 *servname++ = '\0';
66
	 hostname = address;
67
	 memset(&hints, 0, sizeof(hints));
68
	 hints.ai_family = PF_UNSPEC;
69
	 hints.ai_socktype = SOCK_STREAM;
70
	 hints.ai_flags = AI_NUMERICSERV;
71
	 n = getaddrinfo(hostname, servname, &hints, &res0);
72
	 if (n)
73
		 errx(1, "%s", gai_strerror(n));
74
75
	 for (res = res0; res; res = res->ai_next) {
76
		s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
77
		if (s == -1) {
78
			 cause = "socket";
79
			 continue;
80
		 }
81
82
		 if (connect(s, res->ai_addr, res->ai_addrlen) == -1) {
83
			 cause = "connect";
84
			 save_errno = errno;
85
			 close(s);
86
			 errno = save_errno;
87
			 s = -1;
88
			 continue;
89
		 }
90
91
		 break;
92
	 }
93
94
	 freeaddrinfo(res0);
95
	 if (s == -1)
96
		errx(1, "%s", cause);
97
98
	 return s;
99
}
100
101
static int
102
unix_socket(char *path)
103
{
104
	 struct sockaddr_un	addr;
105
	 int			s;
106
107
	 if ((s = socket(PF_LOCAL, SOCK_STREAM, 0)) == -1)
108
		 err(1, "socket");
109
110
	 memset(&addr, 0, sizeof(addr));
111
	 addr.sun_family = AF_UNIX;
112
	 if (strlcpy(addr.sun_path, path, sizeof(addr.sun_path))
113
	     >= sizeof(addr.sun_path))
114
		 errx(1, "socket path too long");
115
116
	 if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) == -1)
117
		 err(1, "connect");
118
119
	 return s;
120
}
121
122
static void
123
lmtp_open(struct deliver *deliver)
124
{
125
	FILE		*fp;
126
	char		*buf = NULL, hn[HOST_NAME_MAX + 1],
127
			*rcpt = deliver->to, *to = deliver->to;
128
	size_t		 sz = 0;
129
	ssize_t		 len;
130
	int		 s;
131
132
	strsep(&rcpt, " ");
133
	s = (to[0] == '/') ? unix_socket(to) : inet_socket(to);
134
	if ((fp = fdopen(s, "r+")) == NULL)
135
		err(1, "fdopen");
136
137
	if (lmtp_banner(&buf, &sz, '2', fp) != 0)
138
		errx(1, "Invalid LHLO reply: %s", buf);
139
140
	if (gethostname(hn, sizeof hn) == -1)
141
		err(1, "gethostname");
142
143
	if (lmtp_cmd(&buf, &sz, '2', fp, "LHLO %s", hn) != 0)
144
		errx(1, "Invalid LHLO reply: %s", buf);
145
146
	if (lmtp_cmd(&buf, &sz, '2', fp, "MAIL FROM:<%s>", deliver->from) != 0)
147
		errx(1, "MAIL FROM rejected: %s", buf);
148
149
	if (lmtp_cmd(&buf, &sz, '2', fp, "RCPT TO:<%s>",
150
	    rcpt ? deliver->dest : deliver->user) != 0)
151
		errx(1, "RCPT TO rejected: %s", buf);
152
153
	if (lmtp_cmd(&buf, &sz, '3', fp, "DATA") != 0)
154
		errx(1, "Invalid DATA reply: %s", buf);
155
156
	while ((len = getline(&buf, &sz, stdin)) != -1) {
157
		if (buf[len - 1] == '\n')
158
			buf[len - 1] = '\0';
159
160
		if (fprintf(fp, "%s%s\r\n", buf[0] == '.' ? "." : "", buf) < 0)
161
			errx(1, "fprintf failed");
162
	}
163
164
	if (lmtp_cmd(&buf, &sz, '2', fp, ".") != 0)
165
		errx(1, "Delivery error: %s", buf);
166
167
	if (lmtp_cmd(&buf, &sz, '2', fp, "QUIT") != 0)
168
		errx(1, "Error on QUIT: %s", buf);
169
170
	exit(0);
171
}
172
173
static int
174
lmtp_banner(char **buf, size_t *sz, int code, FILE *fp)
175
{
176
	char	*bufp;
177
	ssize_t	 len;
178
	size_t	 counter;
179
180
	counter = 0;
181
	do {
182
		if ((len = getline(buf, sz, fp)) == -1)
183
			err(1, "getline");
184
		if (len < 4)
185
			err(1, "line too short");
186
187
		bufp = *buf;
188
		if (len >= 2 && bufp[len - 2] == '\r')
189
			bufp[len - 2] = '\0';
190
		else if (bufp[len - 1] == '\n')
191
			bufp[len - 1] = '\0';
192
193
		if (bufp[3] == '\0' || bufp[3] == ' ')
194
			break;
195
		else if (bufp[3] == '-') {
196
			if (counter == MAX_CONTINUATIONS)
197
				errx(1, "LMTP server is sending too many continuations");
198
			counter++;
199
			continue;
200
		}
201
		else
202
			errx(1, "invalid line");
203
	} while (1);
204
205
	return bufp[0] != code;
206
}
207
208
static int
209
lmtp_cmd(char **buf, size_t *sz, int code, FILE *fp, const char *fmt, ...)
210
{
211
	va_list	 ap;
212
	char	*bufp;
213
	ssize_t	 len;
214
	size_t	 counter;
215
216
	va_start(ap, fmt);
217
	if (vfprintf(fp, fmt, ap) < 0)
218
		errx(1, "vfprintf failed");
219
220
	va_end(ap);
221
	if (fprintf(fp, "\r\n") < 0)
222
		errx(1, "fprintf failed");
223
224
	if (fflush(fp) != 0)
225
		err(1, "fflush");
226
227
	counter = 0;
228
	do {
229
		if ((len = getline(buf, sz, fp)) == -1)
230
			err(1, "getline");
231
		if (len < 4)
232
			err(1, "line too short");
233
234
		bufp = *buf;
235
		if (len >= 2 && bufp[len - 2] == '\r')
236
			bufp[len - 2] = '\0';
237
		else if (bufp[len - 1] == '\n')
238
			bufp[len - 1] = '\0';
239
240
		if (bufp[3] == '\0' || bufp[3] == ' ')
241
			break;
242
		else if (bufp[3] == '-') {
243
			if (counter == MAX_CONTINUATIONS)
244
				errx(1, "LMTP server is sending too many continuations");
245
			counter++;
246
			continue;
247
		}
248
		else
249
			errx(1, "invalid line");
250
	} while (1);
251
252
	return bufp[0] != code;
253
}