xref: /freebsd/contrib/sendmail/libmilter/smfi.c (revision 5521ff5a4d1929056e7ffc982fac3341ca54df7c)
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: smfi.c,v 8.28.4.6 2000/06/28 23:48:56 gshapiro Exp $";
13 #endif /* ! lint */
14 
15 #if _FFR_MILTER
16 #include "libmilter.h"
17 #include "sendmail/useful.h"
18 
19 /*
20 **  SMFI_ADDHEADER -- send a new header to the MTA
21 **
22 **	Parameters:
23 **		ctx -- Opaque context structure
24 **		headerf -- Header field name
25 **		headerv -- Header field value
26 **
27 **	Returns:
28 **		MI_SUCCESS/MI_FAILURE
29 */
30 
31 int
32 smfi_addheader(ctx, headerf, headerv)
33 	SMFICTX *ctx;
34 	char *headerf;
35 	char *headerv;
36 {
37 	/* do we want to copy the stuff or have a special mi_wr_cmd call? */
38 	size_t len, l1, l2;
39 	int r;
40 	char *buf;
41 	struct timeval timeout;
42 
43 	if (headerf == NULL || *headerf == '\0' || headerv == NULL)
44 		return MI_FAILURE;
45 	if (!mi_sendok(ctx, SMFIF_ADDHDRS))
46 		return MI_FAILURE;
47 	timeout.tv_sec = ctx->ctx_timeout;
48 	timeout.tv_usec = 0;
49 	l1 = strlen(headerf);
50 	l2 = strlen(headerv);
51 	len = l1 + l2 + 2;
52 	buf = malloc(len);
53 	if (buf == NULL)
54 		return MI_FAILURE;
55 	(void) memcpy(buf, headerf, l1 + 1);
56 	(void) memcpy(buf + l1 + 1, headerv, l2 + 1);
57 	r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_ADDHEADER, buf, len);
58 	free(buf);
59 	return r;
60 }
61 
62 /*
63 **  SMFI_CHGHEADER -- send a changed header to the MTA
64 **
65 **	Parameters:
66 **		ctx -- Opaque context structure
67 **		headerf -- Header field name
68 **		hdridx -- Header index value
69 **		headerv -- Header field value
70 **
71 **	Returns:
72 **		MI_SUCCESS/MI_FAILURE
73 */
74 
75 int
76 smfi_chgheader(ctx, headerf, hdridx, headerv)
77 	SMFICTX *ctx;
78 	char *headerf;
79 	mi_int32 hdridx;
80 	char *headerv;
81 {
82 	/* do we want to copy the stuff or have a special mi_wr_cmd call? */
83 	size_t len, l1, l2;
84 	int r;
85 	mi_int32 v;
86 	char *buf;
87 	struct timeval timeout;
88 
89 	if (headerf == NULL || *headerf == '\0')
90 		return MI_FAILURE;
91 	if (hdridx < 0)
92 		return MI_FAILURE;
93 	if (!mi_sendok(ctx, SMFIF_CHGHDRS))
94 		return MI_FAILURE;
95 	timeout.tv_sec = ctx->ctx_timeout;
96 	timeout.tv_usec = 0;
97 	if (headerv == NULL)
98 		headerv = "";
99 	l1 = strlen(headerf);
100 	l2 = strlen(headerv);
101 	len = l1 + l2 + 2 + MILTER_LEN_BYTES;
102 	buf = malloc(len);
103 	if (buf == NULL)
104 		return MI_FAILURE;
105 	v = htonl(hdridx);
106 	(void) memcpy(&(buf[0]), (void *) &v, MILTER_LEN_BYTES);
107 	(void) memcpy(buf + MILTER_LEN_BYTES, headerf, l1 + 1);
108 	(void) memcpy(buf + MILTER_LEN_BYTES + l1 + 1, headerv, l2 + 1);
109 	r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_CHGHEADER, buf, len);
110 	free(buf);
111 	return r;
112 }
113 /*
114 **  SMFI_ADDRCPT -- send an additional recipient to the MTA
115 **
116 **	Parameters:
117 **		ctx -- Opaque context structure
118 **		rcpt -- recipient address
119 **
120 **	Returns:
121 **		MI_SUCCESS/MI_FAILURE
122 */
123 
124 int
125 smfi_addrcpt(ctx, rcpt)
126 	SMFICTX *ctx;
127 	char *rcpt;
128 {
129 	size_t len;
130 	struct timeval timeout;
131 
132 	if (rcpt == NULL || *rcpt == '\0')
133 		return MI_FAILURE;
134 	if (!mi_sendok(ctx, SMFIF_ADDRCPT))
135 		return MI_FAILURE;
136 	timeout.tv_sec = ctx->ctx_timeout;
137 	timeout.tv_usec = 0;
138 	len = strlen(rcpt) + 1;
139 	return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_ADDRCPT, rcpt, len);
140 }
141 /*
142 **  SMFI_DELRCPT -- send a recipient to be removed to the MTA
143 **
144 **	Parameters:
145 **		ctx -- Opaque context structure
146 **		rcpt -- recipient address
147 **
148 **	Returns:
149 **		MI_SUCCESS/MI_FAILURE
150 */
151 
152 int
153 smfi_delrcpt(ctx, rcpt)
154 	SMFICTX *ctx;
155 	char *rcpt;
156 {
157 	size_t len;
158 	struct timeval timeout;
159 
160 	if (rcpt == NULL || *rcpt == '\0')
161 		return MI_FAILURE;
162 	if (!mi_sendok(ctx, SMFIF_DELRCPT))
163 		return MI_FAILURE;
164 	timeout.tv_sec = ctx->ctx_timeout;
165 	timeout.tv_usec = 0;
166 	len = strlen(rcpt) + 1;
167 	return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_DELRCPT, rcpt, len);
168 }
169 /*
170 **  SMFI_REPLACEBODY -- send a body chunk to the MTA
171 **
172 **	Parameters:
173 **		ctx -- Opaque context structure
174 **		bodyp -- body chunk
175 **		bodylen -- length of body chunk
176 **
177 **	Returns:
178 **		MI_SUCCESS/MI_FAILURE
179 */
180 
181 int
182 smfi_replacebody(ctx, bodyp, bodylen)
183 	SMFICTX *ctx;
184 	u_char *bodyp;
185 	int bodylen;
186 {
187 	int len, off, r;
188 	struct timeval timeout;
189 
190 	if (bodyp == NULL && bodylen > 0)
191 		return MI_FAILURE;
192 	if (!mi_sendok(ctx, SMFIF_CHGBODY))
193 		return MI_FAILURE;
194 	timeout.tv_sec = ctx->ctx_timeout;
195 	timeout.tv_usec = 0;
196 
197 	/* split body chunk if necessary */
198 	off = 0;
199 	while (bodylen > 0)
200 	{
201 		len = (bodylen >= MILTER_CHUNK_SIZE) ? MILTER_CHUNK_SIZE :
202 						       bodylen;
203 		if ((r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_REPLBODY,
204 				(char *) (bodyp + off), len)) != MI_SUCCESS)
205 			return r;
206 		off += len;
207 		bodylen -= len;
208 	}
209 	return MI_SUCCESS;
210 }
211 /*
212 **  MYISENHSC -- check whether a string contains an enhanced status code
213 **
214 **	Parameters:
215 **		s -- string with possible enhanced status code.
216 **		delim -- delim for enhanced status code.
217 **
218 **	Returns:
219 **		0  -- no enhanced status code.
220 **		>4 -- length of enhanced status code.
221 **
222 **	Side Effects:
223 **		none.
224 */
225 static int
226 myisenhsc(s, delim)
227 	const char *s;
228 	int delim;
229 {
230 	int l, h;
231 
232 	if (s == NULL)
233 		return 0;
234 	if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.'))
235 		return 0;
236 	h = 0;
237 	l = 2;
238 	while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
239 		++h;
240 	if (h == 0 || s[l + h] != '.')
241 		return 0;
242 	l += h + 1;
243 	h = 0;
244 	while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
245 		++h;
246 	if (h == 0 || s[l + h] != delim)
247 		return 0;
248 	return l + h;
249 }
250 /*
251 **  SMFI_SETREPLY -- set the reply code for the next reply to the MTA
252 **
253 **	Parameters:
254 **		ctx -- Opaque context structure
255 **		rcode -- The three-digit (RFC 821) SMTP reply code.
256 **		xcode -- The extended (RFC 2034) reply code.
257 **		message -- The text part of the SMTP reply.
258 **
259 **	Returns:
260 **		MI_SUCCESS/MI_FAILURE
261 */
262 
263 int
264 smfi_setreply(ctx, rcode, xcode, message)
265 	SMFICTX *ctx;
266 	char *rcode;
267 	char *xcode;
268 	char *message;
269 {
270 	size_t len, l1, l2, l3;
271 	char *buf;
272 
273 	if (rcode == NULL || ctx == NULL)
274 		return MI_FAILURE;
275 	l1 = strlen(rcode) + 1;
276 	if (l1 != 4)
277 		return MI_FAILURE;
278 	if ((rcode[0] != '4' && rcode[0] != '5') ||
279 	    !isascii(rcode[1]) || !isdigit(rcode[1]) ||
280 	    !isascii(rcode[2]) || !isdigit(rcode[2]))
281 		return MI_FAILURE;
282 	l2 = xcode == NULL ? 1 : strlen(xcode) + 1;
283 	if (xcode != NULL && !myisenhsc(xcode, '\0'))
284 		return MI_FAILURE;
285 	l3 = message == NULL ? 1 : strlen(message) + 1;
286 	len = l1 + l2 + l3;
287 	buf = malloc(len);
288 	if (buf == NULL)
289 		return MI_FAILURE;		/* oops */
290 	(void) snprintf(buf, len, "%s %s %s", rcode,
291 			xcode == NULL ? "" : xcode,
292 			message == NULL ? "" : message);
293 	if (ctx->ctx_reply != NULL)
294 		free(ctx->ctx_reply);
295 	ctx->ctx_reply = buf;
296 	return MI_SUCCESS;
297 }
298 /*
299 **  SMFI_SETPRIV -- set private data
300 **
301 **	Parameters:
302 **		ctx -- Opaque context structure
303 **		privatedata -- pointer to private data
304 **
305 **	Returns:
306 **		MI_SUCCESS/MI_FAILURE
307 */
308 
309 int
310 smfi_setpriv(ctx, privatedata)
311 	SMFICTX *ctx;
312 	void *privatedata;
313 {
314 	if (ctx == NULL)
315 		return MI_FAILURE;
316 	ctx->ctx_privdata = privatedata;
317 	return MI_SUCCESS;
318 }
319 /*
320 **  SMFI_GETPRIV -- get private data
321 **
322 **	Parameters:
323 **		ctx -- Opaque context structure
324 **
325 **	Returns:
326 **		pointer to private data
327 */
328 
329 void *
330 smfi_getpriv(ctx)
331 	SMFICTX *ctx;
332 {
333 	if (ctx == NULL)
334 		return NULL;
335 	return ctx->ctx_privdata;
336 }
337 /*
338 **  SMFI_GETSYMVAL -- get the value of a macro
339 **
340 **	See explanation in mfapi.h about layout of the structures.
341 **
342 **	Parameters:
343 **		ctx -- Opaque context structure
344 **		symname -- name of macro
345 **
346 **	Returns:
347 **		value of macro (NULL in case of failure)
348 */
349 
350 char *
351 smfi_getsymval(ctx, symname)
352 	SMFICTX *ctx;
353 	char *symname;
354 {
355 	int i;
356 	char **s;
357 	char one[2];
358 	char braces[4];
359 
360 	if (ctx == NULL || symname == NULL || *symname == '\0')
361 		return NULL;
362 
363 	if (strlen(symname) == 3 && symname[0] == '{' && symname[2] == '}')
364 	{
365 		one[0] = symname[1];
366 		one[1] = '\0';
367 	}
368 	else
369 		one[0] = '\0';
370 	if (strlen(symname) == 1)
371 	{
372 		braces[0] = '{';
373 		braces[1] = *symname;
374 		braces[2] = '}';
375 		braces[3] = '\0';
376 	}
377 	else
378 		braces[0] = '\0';
379 
380 	/* search backwards through the macro array */
381 	for (i = MAX_MACROS_ENTRIES - 1 ; i >= 0; --i)
382 	{
383 		if ((s = ctx->ctx_mac_ptr[i]) == NULL ||
384 		    ctx->ctx_mac_buf[i] == NULL)
385 			continue;
386 		while (s != NULL && *s != NULL)
387 		{
388 			if (strcmp(*s, symname) == 0)
389 				return *++s;
390 			if (one[0] != '\0' && strcmp(*s, one) == 0)
391 				return *++s;
392 			if (braces[0] != '\0' && strcmp(*s, braces) == 0)
393 				return *++s;
394 			++s;	/* skip over macro value */
395 			++s;	/* points to next macro name */
396 		}
397 	}
398 	return NULL;
399 }
400 #endif /* _FFR_MILTER */
401