xref: /freebsd/contrib/sendmail/libmilter/comm.c (revision 17d6c636720d00f77e5d098daf4c278f89d84f7b)
1 /*
2  *  Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers.
3  *	All rights reserved.
4  *
5  * By using this file, you agree to the terms and conditions set
6  * forth in the LICENSE file which can be found at the top level of
7  * the sendmail distribution.
8  *
9  */
10 
11 #ifndef lint
12 static char id[] = "@(#)$Id: comm.c,v 8.30.4.6 2000/10/05 22:44:01 gshapiro Exp $";
13 #endif /* ! lint */
14 
15 #if _FFR_MILTER
16 #include "libmilter.h"
17 
18 #define FD_Z	FD_ZERO(&readset);	\
19 		FD_SET((u_int) sd, &readset);	\
20 		FD_ZERO(&excset);	\
21 		FD_SET((u_int) sd, &excset)
22 
23 /*
24 **  MI_RD_CMD -- read a command
25 **
26 **	Parameters:
27 **		sd -- socket descriptor
28 **		timeout -- maximum time to wait
29 **		cmd -- single character command read from sd
30 **		rlen -- pointer to length of result
31 **		name -- name of milter
32 **
33 **	Returns:
34 **		buffer with rest of command
35 **		(malloc()ed here, should be free()d)
36 **		hack: encode error in cmd
37 */
38 
39 char *
40 mi_rd_cmd(sd, timeout, cmd, rlen, name)
41 	socket_t sd;
42 	struct timeval *timeout;
43 	char *cmd;
44 	size_t *rlen;
45 	char *name;
46 {
47 	ssize_t len;
48 	mi_int32 expl;
49 	ssize_t i;
50 	fd_set readset, excset;
51 	int ret;
52 	int save_errno;
53 	char *buf;
54 	char data[MILTER_LEN_BYTES + 1];
55 
56 	*cmd = '\0';
57 	*rlen = 0;
58 
59 	if (sd >= FD_SETSIZE)
60 	{
61 		smi_log(SMI_LOG_ERR, "%s: fd %d is larger than FD_SETSIZE %d",
62 			name, sd, FD_SETSIZE);
63 		*cmd = SMFIC_SELECT;
64 		return NULL;
65 	}
66 
67 	FD_Z;
68 	i = 0;
69 	while ((ret = select(sd + 1, &readset, NULL, &excset, timeout)) >= 1)
70 	{
71 		if (FD_ISSET(sd, &excset))
72 		{
73 			*cmd = SMFIC_SELECT;
74 			return NULL;
75 		}
76 		if ((len = MI_SOCK_READ(sd, data + i, sizeof data - i)) < 0)
77 		{
78 			smi_log(SMI_LOG_ERR,
79 				"%s, mi_rd_cmd: read returned %d: %s",
80 				name, len, strerror(errno));
81 			*cmd = SMFIC_RECVERR;
82 			return NULL;
83 		}
84 		if (len == 0)
85 		{
86 			*cmd = SMFIC_EOF;
87 			return NULL;
88 		}
89 		if (len >= (ssize_t) sizeof data - i)
90 			break;
91 		i += len;
92 		FD_Z;
93 	}
94 	if (ret == 0)
95 	{
96 		*cmd = SMFIC_TIMEOUT;
97 		return NULL;
98 	}
99 	else if (ret < 0)
100 	{
101 		smi_log(SMI_LOG_ERR,
102 			"%s: mi_rd_cmd: select returned %d: %s",
103 			name, ret, strerror(errno));
104 		*cmd = SMFIC_RECVERR;
105 		return NULL;
106 	}
107 
108 	*cmd = data[MILTER_LEN_BYTES];
109 	data[MILTER_LEN_BYTES] = '\0';
110 	(void) memcpy((void *) &expl, (void *) &(data[0]), MILTER_LEN_BYTES);
111 	expl = ntohl(expl) - 1;
112 	if (expl <= 0)
113 		return NULL;
114 	if (expl > MILTER_CHUNK_SIZE)
115 	{
116 		*cmd = SMFIC_TOOBIG;
117 		return NULL;
118 	}
119 	buf = malloc(expl);
120 	if (buf == NULL)
121 	{
122 		*cmd = SMFIC_MALLOC;
123 		return NULL;
124 	}
125 
126 	i = 0;
127 	FD_Z;
128 	while ((ret = select(sd + 1, &readset, NULL, &excset, timeout)) == 1)
129 	{
130 		if (FD_ISSET(sd, &excset))
131 		{
132 			*cmd = SMFIC_SELECT;
133 			free(buf);
134 			return NULL;
135 		}
136 		if ((len = MI_SOCK_READ(sd, buf + i, expl - i)) < 0)
137 		{
138 			smi_log(SMI_LOG_ERR,
139 				"%s: mi_rd_cmd: read returned %d: %s",
140 				name, len, strerror(errno));
141 			ret = -1;
142 			break;
143 		}
144 		if (len == 0)
145 		{
146 			*cmd = SMFIC_EOF;
147 			free(buf);
148 			return NULL;
149 		}
150 		if (len > expl - i)
151 		{
152 			*cmd = SMFIC_RECVERR;
153 			free(buf);
154 			return NULL;
155 		}
156 		if (len >= expl - i)
157 		{
158 			*rlen = expl;
159 			return buf;
160 		}
161 		i += len;
162 		FD_Z;
163 	}
164 
165 	save_errno = errno;
166 	free(buf);
167 
168 	/* select returned 0 (timeout) or < 0 (error) */
169 	if (ret == 0)
170 	{
171 		*cmd = SMFIC_TIMEOUT;
172 		return NULL;
173 	}
174 	if (ret < 0)
175 	{
176 		smi_log(SMI_LOG_ERR,
177 			"%s: mi_rd_cmd: select returned %d: %s",
178 			name, ret, strerror(save_errno));
179 		*cmd = SMFIC_RECVERR;
180 		return NULL;
181 	}
182 	*cmd = SMFIC_UNKNERR;
183 	return NULL;
184 }
185 /*
186 **  MI_WR_CMD -- write a cmd to sd
187 **
188 **	Parameters:
189 **		sd -- socket descriptor
190 **		timeout -- maximum time to wait (currently unused)
191 **		cmd -- single character command to write
192 **		buf -- buffer with further data
193 **		len -- length of buffer (without cmd!)
194 **
195 **	Returns:
196 **		MI_SUCCESS/MI_FAILURE
197 */
198 
199 int
200 mi_wr_cmd(sd, timeout, cmd, buf, len)
201 	socket_t sd;
202 	struct timeval *timeout;
203 	int cmd;
204 	char *buf;
205 	size_t len;
206 {
207 	size_t sl, i;
208 	ssize_t l;
209 	mi_int32 nl;
210 	int ret;
211 	fd_set wrtset;
212 	char data[MILTER_LEN_BYTES + 1];
213 
214 	if (len > MILTER_CHUNK_SIZE)
215 		return MI_FAILURE;
216 	nl = htonl(len + 1);	/* add 1 for the cmd char */
217 	(void) memcpy(data, (void *) &nl, MILTER_LEN_BYTES);
218 	data[MILTER_LEN_BYTES] = (char) cmd;
219 	i = 0;
220 	sl = MILTER_LEN_BYTES + 1;
221 
222 	do
223 	{
224 		FD_ZERO(&wrtset);
225 		FD_SET((u_int) sd, &wrtset);
226 		if ((ret = select(sd + 1, NULL, &wrtset, NULL, timeout)) == 0)
227 			return MI_FAILURE;
228 	} while (ret < 0 && errno == EINTR);
229 	if (ret < 0)
230 		return MI_FAILURE;
231 
232 	/* use writev() instead to send the whole stuff at once? */
233 	while ((l = MI_SOCK_WRITE(sd, (void *) (data + i),
234 				  sl - i)) < (ssize_t) sl)
235 	{
236 		if (l < 0)
237 			return MI_FAILURE;
238 		i += l;
239 		sl -= l;
240 	}
241 
242 	if (len > 0 && buf == NULL)
243 		return MI_FAILURE;
244 	if (len == 0 || buf == NULL)
245 		return MI_SUCCESS;
246 	i = 0;
247 	sl = len;
248 	do
249 	{
250 		FD_ZERO(&wrtset);
251 		FD_SET((u_int) sd, &wrtset);
252 		if ((ret = select(sd + 1, NULL, &wrtset, NULL, timeout)) == 0)
253 			return MI_FAILURE;
254 	} while (ret < 0 && errno == EINTR);
255 	if (ret < 0)
256 		return MI_FAILURE;
257 	while ((l = MI_SOCK_WRITE(sd, (void *) (buf + i),
258 				  sl - i)) < (ssize_t) sl)
259 	{
260 		if (l < 0)
261 			return MI_FAILURE;
262 		i += l;
263 		sl -= l;
264 	}
265 	return MI_SUCCESS;
266 }
267 #endif /* _FFR_MILTER */
268