comm.c revision 256281
1132400Sgrehan/*
2132400Sgrehan *  Copyright (c) 1999-2004, 2009 Sendmail, Inc. and its suppliers.
3132400Sgrehan *	All rights reserved.
4132400Sgrehan *
5132400Sgrehan * By using this file, you agree to the terms and conditions set
6132400Sgrehan * forth in the LICENSE file which can be found at the top level of
7132400Sgrehan * the sendmail distribution.
8132400Sgrehan *
9132400Sgrehan */
10132400Sgrehan
11132400Sgrehan#include <sm/gen.h>
12132400SgrehanSM_RCSID("@(#)$Id: comm.c,v 8.70 2009/12/16 16:33:48 ca Exp $")
13132400Sgrehan
14132400Sgrehan#include "libmilter.h"
15132400Sgrehan#include <sm/errstring.h>
16132400Sgrehan#include <sys/uio.h>
17132400Sgrehan
18132400Sgrehanstatic ssize_t	retry_writev __P((socket_t, struct iovec *, int, struct timeval *));
19132400Sgrehanstatic size_t Maxdatasize = MILTER_MAX_DATA_SIZE;
20132400Sgrehan
21132400Sgrehan/*
22132400Sgrehan**  SMFI_SETMAXDATASIZE -- set limit for milter data read/write.
23132400Sgrehan**
24132400Sgrehan**	Parameters:
25132400Sgrehan**		sz -- new limit.
26132400Sgrehan**
27132400Sgrehan**	Returns:
28132400Sgrehan**		old limit
29132400Sgrehan*/
30132400Sgrehan
31132400Sgrehansize_t
32132400Sgrehansmfi_setmaxdatasize(sz)
33132400Sgrehan	size_t sz;
34132400Sgrehan{
35132400Sgrehan	size_t old;
36132400Sgrehan
37132400Sgrehan	old = Maxdatasize;
38132400Sgrehan	Maxdatasize = sz;
39132400Sgrehan	return old;
40132400Sgrehan}
41132400Sgrehan
42132400Sgrehan/*
43132400Sgrehan**  MI_RD_CMD -- read a command
44132400Sgrehan**
45132400Sgrehan**	Parameters:
46132400Sgrehan**		sd -- socket descriptor
47132400Sgrehan**		timeout -- maximum time to wait
48132400Sgrehan**		cmd -- single character command read from sd
49132400Sgrehan**		rlen -- pointer to length of result
50132400Sgrehan**		name -- name of milter
51132400Sgrehan**
52132400Sgrehan**	Returns:
53132400Sgrehan**		buffer with rest of command
54132400Sgrehan**		(malloc()ed here, should be free()d)
55132400Sgrehan**		hack: encode error in cmd
56132400Sgrehan*/
57132400Sgrehan
58132400Sgrehanchar *
59132400Sgrehanmi_rd_cmd(sd, timeout, cmd, rlen, name)
60132400Sgrehan	socket_t sd;
61132400Sgrehan	struct timeval *timeout;
62132400Sgrehan	char *cmd;
63132400Sgrehan	size_t *rlen;
64132400Sgrehan	char *name;
65132400Sgrehan{
66132400Sgrehan	ssize_t len;
67132400Sgrehan	mi_int32 expl;
68132400Sgrehan	ssize_t i;
69132400Sgrehan	FD_RD_VAR(rds, excs);
70132400Sgrehan	int ret;
71132400Sgrehan	int save_errno;
72132400Sgrehan	char *buf;
73132400Sgrehan	char data[MILTER_LEN_BYTES + 1];
74132400Sgrehan
75132400Sgrehan	*cmd = '\0';
76132400Sgrehan	*rlen = 0;
77132400Sgrehan
78132400Sgrehan	i = 0;
79132400Sgrehan	for (;;)
80132400Sgrehan	{
81132400Sgrehan		FD_RD_INIT(sd, rds, excs);
82132400Sgrehan		ret = FD_RD_READY(sd, rds, excs, timeout);
83132400Sgrehan		if (ret == 0)
84132400Sgrehan			break;
85132400Sgrehan		else if (ret < 0)
86132400Sgrehan		{
87132400Sgrehan			if (errno == EINTR)
88132400Sgrehan				continue;
89132400Sgrehan			break;
90132400Sgrehan		}
91132400Sgrehan		if (FD_IS_RD_EXC(sd, rds, excs))
92132400Sgrehan		{
93132400Sgrehan			*cmd = SMFIC_SELECT;
94132400Sgrehan			return NULL;
95132400Sgrehan		}
96132400Sgrehan
97132400Sgrehan		len = MI_SOCK_READ(sd, data + i, sizeof data - i);
98132400Sgrehan		if (MI_SOCK_READ_FAIL(len))
99132400Sgrehan		{
100132400Sgrehan			smi_log(SMI_LOG_ERR,
101132400Sgrehan				"%s, mi_rd_cmd: read returned %d: %s",
102132400Sgrehan				name, (int) len, sm_errstring(errno));
103132400Sgrehan			*cmd = SMFIC_RECVERR;
104132400Sgrehan			return NULL;
105132400Sgrehan		}
106132400Sgrehan		if (len == 0)
107132400Sgrehan		{
108132400Sgrehan			*cmd = SMFIC_EOF;
109132400Sgrehan			return NULL;
110132400Sgrehan		}
111132400Sgrehan		if (len >= (ssize_t) sizeof data - i)
112132400Sgrehan			break;
113132400Sgrehan		i += len;
114	}
115	if (ret == 0)
116	{
117		*cmd = SMFIC_TIMEOUT;
118		return NULL;
119	}
120	else if (ret < 0)
121	{
122		smi_log(SMI_LOG_ERR,
123			"%s: mi_rd_cmd: %s() returned %d: %s",
124			name, MI_POLLSELECT, ret, sm_errstring(errno));
125		*cmd = SMFIC_RECVERR;
126		return NULL;
127	}
128
129	*cmd = data[MILTER_LEN_BYTES];
130	data[MILTER_LEN_BYTES] = '\0';
131	(void) memcpy((void *) &expl, (void *) &(data[0]), MILTER_LEN_BYTES);
132	expl = ntohl(expl) - 1;
133	if (expl <= 0)
134		return NULL;
135	if (expl > Maxdatasize)
136	{
137		*cmd = SMFIC_TOOBIG;
138		return NULL;
139	}
140#if _FFR_ADD_NULL
141	buf = malloc(expl + 1);
142#else /* _FFR_ADD_NULL */
143	buf = malloc(expl);
144#endif /* _FFR_ADD_NULL */
145	if (buf == NULL)
146	{
147		*cmd = SMFIC_MALLOC;
148		return NULL;
149	}
150
151	i = 0;
152	for (;;)
153	{
154		FD_RD_INIT(sd, rds, excs);
155		ret = FD_RD_READY(sd, rds, excs, timeout);
156		if (ret == 0)
157			break;
158		else if (ret < 0)
159		{
160			if (errno == EINTR)
161				continue;
162			break;
163		}
164		if (FD_IS_RD_EXC(sd, rds, excs))
165		{
166			*cmd = SMFIC_SELECT;
167			free(buf);
168			return NULL;
169		}
170		len = MI_SOCK_READ(sd, buf + i, expl - i);
171		if (MI_SOCK_READ_FAIL(len))
172		{
173			smi_log(SMI_LOG_ERR,
174				"%s: mi_rd_cmd: read returned %d: %s",
175				name, (int) len, sm_errstring(errno));
176			ret = -1;
177			break;
178		}
179		if (len == 0)
180		{
181			*cmd = SMFIC_EOF;
182			free(buf);
183			return NULL;
184		}
185		if (len > expl - i)
186		{
187			*cmd = SMFIC_RECVERR;
188			free(buf);
189			return NULL;
190		}
191		if (len >= expl - i)
192		{
193			*rlen = expl;
194#if _FFR_ADD_NULL
195			/* makes life simpler for common string routines */
196			buf[expl] = '\0';
197#endif /* _FFR_ADD_NULL */
198			return buf;
199		}
200		i += len;
201	}
202
203	save_errno = errno;
204	free(buf);
205
206	/* select returned 0 (timeout) or < 0 (error) */
207	if (ret == 0)
208	{
209		*cmd = SMFIC_TIMEOUT;
210		return NULL;
211	}
212	if (ret < 0)
213	{
214		smi_log(SMI_LOG_ERR,
215			"%s: mi_rd_cmd: %s() returned %d: %s",
216			name, MI_POLLSELECT, ret, sm_errstring(save_errno));
217		*cmd = SMFIC_RECVERR;
218		return NULL;
219	}
220	*cmd = SMFIC_UNKNERR;
221	return NULL;
222}
223
224/*
225**  RETRY_WRITEV -- Keep calling the writev() system call
226**	until all the data is written out or an error occurs.
227**
228**	Parameters:
229**		fd -- socket descriptor
230**		iov -- io vector
231**		iovcnt -- number of elements in io vector
232**			must NOT exceed UIO_MAXIOV.
233**		timeout -- maximum time to wait
234**
235**	Returns:
236**		success: number of bytes written
237**		otherwise: MI_FAILURE
238*/
239
240static ssize_t
241retry_writev(fd, iov, iovcnt, timeout)
242	socket_t fd;
243	struct iovec *iov;
244	int iovcnt;
245	struct timeval *timeout;
246{
247	int i;
248	ssize_t n, written;
249	FD_WR_VAR(wrs);
250
251	written = 0;
252	for (;;)
253	{
254		while (iovcnt > 0 && iov[0].iov_len == 0)
255		{
256			iov++;
257			iovcnt--;
258		}
259		if (iovcnt <= 0)
260			return written;
261
262		/*
263		**  We don't care much about the timeout here,
264		**  it's very long anyway; correct solution would be
265		**  to take the time before the loop and reduce the
266		**  timeout after each invocation.
267		**  FD_SETSIZE is checked when socket is created.
268		*/
269
270		FD_WR_INIT(fd, wrs);
271		i = FD_WR_READY(fd, wrs, timeout);
272		if (i == 0)
273			return MI_FAILURE;
274		if (i < 0)
275		{
276			if (errno == EINTR || errno == EAGAIN)
277				continue;
278			return MI_FAILURE;
279		}
280		n = writev(fd, iov, iovcnt);
281		if (n == -1)
282		{
283			if (errno == EINTR || errno == EAGAIN)
284				continue;
285			return MI_FAILURE;
286		}
287
288		written += n;
289		for (i = 0; i < iovcnt; i++)
290		{
291			if (iov[i].iov_len > (unsigned int) n)
292			{
293				iov[i].iov_base = (char *)iov[i].iov_base + n;
294				iov[i].iov_len -= (unsigned int) n;
295				break;
296			}
297			n -= (int) iov[i].iov_len;
298			iov[i].iov_len = 0;
299		}
300		if (i == iovcnt)
301			return written;
302	}
303}
304
305/*
306**  MI_WR_CMD -- write a cmd to sd
307**
308**	Parameters:
309**		sd -- socket descriptor
310**		timeout -- maximum time to wait
311**		cmd -- single character command to write
312**		buf -- buffer with further data
313**		len -- length of buffer (without cmd!)
314**
315**	Returns:
316**		MI_SUCCESS/MI_FAILURE
317*/
318
319int
320mi_wr_cmd(sd, timeout, cmd, buf, len)
321	socket_t sd;
322	struct timeval *timeout;
323	int cmd;
324	char *buf;
325	size_t len;
326{
327	size_t sl;
328	ssize_t l;
329	mi_int32 nl;
330	int iovcnt;
331	struct iovec iov[2];
332	char data[MILTER_LEN_BYTES + 1];
333
334	if (len > Maxdatasize || (len > 0 && buf == NULL))
335		return MI_FAILURE;
336
337	nl = htonl(len + 1);	/* add 1 for the cmd char */
338	(void) memcpy(data, (void *) &nl, MILTER_LEN_BYTES);
339	data[MILTER_LEN_BYTES] = (char) cmd;
340	sl = MILTER_LEN_BYTES + 1;
341
342	/* set up the vector for the size / command */
343	iov[0].iov_base = (void *) data;
344	iov[0].iov_len  = sl;
345	iovcnt = 1;
346	if (len >= 0 && buf != NULL)
347	{
348		iov[1].iov_base = (void *) buf;
349		iov[1].iov_len  = len;
350		iovcnt = 2;
351	}
352
353	l = retry_writev(sd, iov, iovcnt, timeout);
354	if (l == MI_FAILURE)
355		return MI_FAILURE;
356	return MI_SUCCESS;
357}
358