smfi.c revision 64562
1235368Sgnn/*
2235368Sgnn *  Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers.
3235368Sgnn *	All rights reserved.
4235368Sgnn *
5235368Sgnn * By using this file, you agree to the terms and conditions set
6235368Sgnn * forth in the LICENSE file which can be found at the top level of
7235368Sgnn * the sendmail distribution.
8235368Sgnn *
9235368Sgnn */
10235368Sgnn
11235368Sgnn#ifndef lint
12235368Sgnnstatic char id[] = "@(#)$Id: smfi.c,v 8.28.4.6 2000/06/28 23:48:56 gshapiro Exp $";
13235368Sgnn#endif /* ! lint */
14235368Sgnn
15235368Sgnn#if _FFR_MILTER
16235368Sgnn#include "libmilter.h"
17235368Sgnn#include "sendmail/useful.h"
18235368Sgnn
19235368Sgnn/*
20235368Sgnn**  SMFI_ADDHEADER -- send a new header to the MTA
21235368Sgnn**
22235368Sgnn**	Parameters:
23235368Sgnn**		ctx -- Opaque context structure
24235368Sgnn**		headerf -- Header field name
25235368Sgnn**		headerv -- Header field value
26235368Sgnn**
27235368Sgnn**	Returns:
28235368Sgnn**		MI_SUCCESS/MI_FAILURE
29235368Sgnn*/
30235368Sgnn
31235368Sgnnint
32235368Sgnnsmfi_addheader(ctx, headerf, headerv)
33235368Sgnn	SMFICTX *ctx;
34235368Sgnn	char *headerf;
35235368Sgnn	char *headerv;
36235368Sgnn{
37235368Sgnn	/* do we want to copy the stuff or have a special mi_wr_cmd call? */
38235368Sgnn	size_t len, l1, l2;
39235368Sgnn	int r;
40235368Sgnn	char *buf;
41235368Sgnn	struct timeval timeout;
42235368Sgnn
43235368Sgnn	if (headerf == NULL || *headerf == '\0' || headerv == NULL)
44235368Sgnn		return MI_FAILURE;
45235368Sgnn	if (!mi_sendok(ctx, SMFIF_ADDHDRS))
46235368Sgnn		return MI_FAILURE;
47235368Sgnn	timeout.tv_sec = ctx->ctx_timeout;
48235368Sgnn	timeout.tv_usec = 0;
49235368Sgnn	l1 = strlen(headerf);
50235368Sgnn	l2 = strlen(headerv);
51235368Sgnn	len = l1 + l2 + 2;
52235368Sgnn	buf = malloc(len);
53235368Sgnn	if (buf == NULL)
54235368Sgnn		return MI_FAILURE;
55235368Sgnn	(void) memcpy(buf, headerf, l1 + 1);
56235368Sgnn	(void) memcpy(buf + l1 + 1, headerv, l2 + 1);
57235368Sgnn	r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_ADDHEADER, buf, len);
58235368Sgnn	free(buf);
59235368Sgnn	return r;
60235368Sgnn}
61235368Sgnn
62235368Sgnn/*
63235368Sgnn**  SMFI_CHGHEADER -- send a changed header to the MTA
64235368Sgnn**
65235368Sgnn**	Parameters:
66235368Sgnn**		ctx -- Opaque context structure
67235368Sgnn**		headerf -- Header field name
68235368Sgnn**		hdridx -- Header index value
69235368Sgnn**		headerv -- Header field value
70235368Sgnn**
71235368Sgnn**	Returns:
72235368Sgnn**		MI_SUCCESS/MI_FAILURE
73*/
74
75int
76smfi_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
124int
125smfi_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
152int
153smfi_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
181int
182smfi_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*/
225static int
226myisenhsc(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
263int
264smfi_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
309int
310smfi_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
329void *
330smfi_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
350char *
351smfi_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