164562Sgshapiro/*
2173340Sgshapiro *  Copyright (c) 1999-2007 Sendmail, Inc. and its suppliers.
364562Sgshapiro *	All rights reserved.
464562Sgshapiro *
564562Sgshapiro * By using this file, you agree to the terms and conditions set
664562Sgshapiro * forth in the LICENSE file which can be found at the top level of
764562Sgshapiro * the sendmail distribution.
864562Sgshapiro *
964562Sgshapiro */
1064562Sgshapiro
1190792Sgshapiro#include <sm/gen.h>
12173340SgshapiroSM_RCSID("@(#)$Id: smfi.c,v 8.83 2007/04/23 16:44:39 ca Exp $")
1390792Sgshapiro#include <sm/varargs.h>
1464562Sgshapiro#include "libmilter.h"
1564562Sgshapiro
16132943Sgshapirostatic int smfi_header __P((SMFICTX *, int, int, char *, char *));
17141858Sgshapirostatic int myisenhsc __P((const char *, int));
18132943Sgshapiro
1990792Sgshapiro/* for smfi_set{ml}reply, let's be generous. 256/16 should be sufficient */
2090792Sgshapiro#define MAXREPLYLEN	980	/* max. length of a reply string */
2190792Sgshapiro#define MAXREPLIES	32	/* max. number of reply strings */
2290792Sgshapiro
2364562Sgshapiro/*
24132943Sgshapiro**  SMFI_HEADER -- send a header to the MTA
2564562Sgshapiro**
2664562Sgshapiro**	Parameters:
2764562Sgshapiro**		ctx -- Opaque context structure
28132943Sgshapiro**		cmd -- Header modification command
29132943Sgshapiro**		hdridx -- Header index
3064562Sgshapiro**		headerf -- Header field name
3164562Sgshapiro**		headerv -- Header field value
3264562Sgshapiro**
3364562Sgshapiro**	Returns:
3464562Sgshapiro**		MI_SUCCESS/MI_FAILURE
3564562Sgshapiro*/
3664562Sgshapiro
37132943Sgshapirostatic int
38132943Sgshapirosmfi_header(ctx, cmd, hdridx, headerf, headerv)
3964562Sgshapiro	SMFICTX *ctx;
40132943Sgshapiro	int cmd;
41132943Sgshapiro	int hdridx;
4264562Sgshapiro	char *headerf;
4364562Sgshapiro	char *headerv;
4464562Sgshapiro{
45132943Sgshapiro	size_t len, l1, l2, offset;
4664562Sgshapiro	int r;
47132943Sgshapiro	mi_int32 v;
4864562Sgshapiro	char *buf;
4964562Sgshapiro	struct timeval timeout;
5064562Sgshapiro
5164562Sgshapiro	if (headerf == NULL || *headerf == '\0' || headerv == NULL)
5264562Sgshapiro		return MI_FAILURE;
5364562Sgshapiro	timeout.tv_sec = ctx->ctx_timeout;
5464562Sgshapiro	timeout.tv_usec = 0;
55132943Sgshapiro	l1 = strlen(headerf) + 1;
56132943Sgshapiro	l2 = strlen(headerv) + 1;
57132943Sgshapiro	len = l1 + l2;
58132943Sgshapiro	if (hdridx >= 0)
59132943Sgshapiro		len += MILTER_LEN_BYTES;
6064562Sgshapiro	buf = malloc(len);
6164562Sgshapiro	if (buf == NULL)
6264562Sgshapiro		return MI_FAILURE;
63132943Sgshapiro	offset = 0;
64132943Sgshapiro	if (hdridx >= 0)
65132943Sgshapiro	{
66132943Sgshapiro		v = htonl(hdridx);
67132943Sgshapiro		(void) memcpy(&(buf[0]), (void *) &v, MILTER_LEN_BYTES);
68132943Sgshapiro		offset += MILTER_LEN_BYTES;
69132943Sgshapiro	}
70132943Sgshapiro	(void) memcpy(buf + offset, headerf, l1);
71132943Sgshapiro	(void) memcpy(buf + offset + l1, headerv, l2);
72132943Sgshapiro	r = mi_wr_cmd(ctx->ctx_sd, &timeout, cmd, buf, len);
7364562Sgshapiro	free(buf);
7464562Sgshapiro	return r;
7564562Sgshapiro}
7664562Sgshapiro
7764562Sgshapiro/*
78132943Sgshapiro**  SMFI_ADDHEADER -- send a new header to the MTA
79132943Sgshapiro**
80132943Sgshapiro**	Parameters:
81132943Sgshapiro**		ctx -- Opaque context structure
82132943Sgshapiro**		headerf -- Header field name
83132943Sgshapiro**		headerv -- Header field value
84132943Sgshapiro**
85132943Sgshapiro**	Returns:
86132943Sgshapiro**		MI_SUCCESS/MI_FAILURE
87132943Sgshapiro*/
88132943Sgshapiro
89132943Sgshapiroint
90132943Sgshapirosmfi_addheader(ctx, headerf, headerv)
91132943Sgshapiro	SMFICTX *ctx;
92132943Sgshapiro	char *headerf;
93132943Sgshapiro	char *headerv;
94132943Sgshapiro{
95132943Sgshapiro	if (!mi_sendok(ctx, SMFIF_ADDHDRS))
96132943Sgshapiro		return MI_FAILURE;
97132943Sgshapiro
98132943Sgshapiro	return smfi_header(ctx, SMFIR_ADDHEADER, -1, headerf, headerv);
99132943Sgshapiro}
100132943Sgshapiro
101132943Sgshapiro/*
102132943Sgshapiro**  SMFI_INSHEADER -- send a new header to the MTA (to be inserted)
103132943Sgshapiro**
104132943Sgshapiro**	Parameters:
105132943Sgshapiro**		ctx -- Opaque context structure
106132943Sgshapiro**  		hdridx -- index into header list where insertion should occur
107132943Sgshapiro**		headerf -- Header field name
108132943Sgshapiro**		headerv -- Header field value
109132943Sgshapiro**
110132943Sgshapiro**	Returns:
111132943Sgshapiro**		MI_SUCCESS/MI_FAILURE
112132943Sgshapiro*/
113132943Sgshapiro
114132943Sgshapiroint
115132943Sgshapirosmfi_insheader(ctx, hdridx, headerf, headerv)
116132943Sgshapiro	SMFICTX *ctx;
117132943Sgshapiro	int hdridx;
118132943Sgshapiro	char *headerf;
119132943Sgshapiro	char *headerv;
120132943Sgshapiro{
121132943Sgshapiro	if (!mi_sendok(ctx, SMFIF_ADDHDRS) || hdridx < 0)
122132943Sgshapiro		return MI_FAILURE;
123132943Sgshapiro
124132943Sgshapiro	return smfi_header(ctx, SMFIR_INSHEADER, hdridx, headerf, headerv);
125132943Sgshapiro}
126132943Sgshapiro
127132943Sgshapiro/*
12864562Sgshapiro**  SMFI_CHGHEADER -- send a changed header to the MTA
12964562Sgshapiro**
13064562Sgshapiro**	Parameters:
13164562Sgshapiro**		ctx -- Opaque context structure
13264562Sgshapiro**		headerf -- Header field name
13364562Sgshapiro**		hdridx -- Header index value
13464562Sgshapiro**		headerv -- Header field value
13564562Sgshapiro**
13664562Sgshapiro**	Returns:
13764562Sgshapiro**		MI_SUCCESS/MI_FAILURE
13864562Sgshapiro*/
13964562Sgshapiro
14064562Sgshapiroint
14164562Sgshapirosmfi_chgheader(ctx, headerf, hdridx, headerv)
14264562Sgshapiro	SMFICTX *ctx;
14364562Sgshapiro	char *headerf;
14464562Sgshapiro	mi_int32 hdridx;
14564562Sgshapiro	char *headerv;
14664562Sgshapiro{
147132943Sgshapiro	if (!mi_sendok(ctx, SMFIF_CHGHDRS) || hdridx < 0)
14864562Sgshapiro		return MI_FAILURE;
14964562Sgshapiro	if (headerv == NULL)
15064562Sgshapiro		headerv = "";
151132943Sgshapiro
152132943Sgshapiro	return smfi_header(ctx, SMFIR_CHGHEADER, hdridx, headerf, headerv);
15364562Sgshapiro}
15494334Sgshapiro
155168515Sgshapiro#if 0
15690792Sgshapiro/*
157168515Sgshapiro**  BUF_CRT_SEND -- construct buffer to send from arguments
158168515Sgshapiro**
159168515Sgshapiro**	Parameters:
160168515Sgshapiro**		ctx -- Opaque context structure
161168515Sgshapiro**		cmd -- command
162168515Sgshapiro**		arg0 -- first argument
163168515Sgshapiro**		argv -- list of arguments (NULL terminated)
164168515Sgshapiro**
165168515Sgshapiro**	Returns:
166168515Sgshapiro**		MI_SUCCESS/MI_FAILURE
167168515Sgshapiro*/
168168515Sgshapiro
169168515Sgshapirostatic int
170168515Sgshapirobuf_crt_send __P((SMFICTX *, int cmd, char *, char **));
171168515Sgshapiro
172168515Sgshapirostatic int
173168515Sgshapirobuf_crt_send(ctx, cmd, arg0, argv)
174168515Sgshapiro	SMFICTX *ctx;
175168515Sgshapiro	int cmd;
176168515Sgshapiro	char *arg0;
177168515Sgshapiro	char **argv;
178168515Sgshapiro{
179168515Sgshapiro	size_t len, l0, l1, offset;
180168515Sgshapiro	int r;
181168515Sgshapiro	char *buf, *arg, **argvl;
182168515Sgshapiro	struct timeval timeout;
183168515Sgshapiro
184168515Sgshapiro	if (arg0 == NULL || *arg0 == '\0')
185168515Sgshapiro		return MI_FAILURE;
186168515Sgshapiro	timeout.tv_sec = ctx->ctx_timeout;
187168515Sgshapiro	timeout.tv_usec = 0;
188168515Sgshapiro	l0 = strlen(arg0) + 1;
189168515Sgshapiro	len = l0;
190168515Sgshapiro	argvl = argv;
191168515Sgshapiro	while (argvl != NULL && (arg = *argv) != NULL && *arg != '\0')
192168515Sgshapiro	{
193168515Sgshapiro		l1 = strlen(arg) + 1;
194168515Sgshapiro		len += l1;
195168515Sgshapiro		SM_ASSERT(len > l1);
196168515Sgshapiro	}
197168515Sgshapiro
198168515Sgshapiro	buf = malloc(len);
199168515Sgshapiro	if (buf == NULL)
200168515Sgshapiro		return MI_FAILURE;
201168515Sgshapiro	(void) memcpy(buf, arg0, l0);
202168515Sgshapiro	offset = l0;
203168515Sgshapiro
204168515Sgshapiro	argvl = argv;
205168515Sgshapiro	while (argvl != NULL && (arg = *argv) != NULL && *arg != '\0')
206168515Sgshapiro	{
207168515Sgshapiro		l1 = strlen(arg) + 1;
208168515Sgshapiro		SM_ASSERT(offset < len);
209168515Sgshapiro		SM_ASSERT(offset + l1 <= len);
210168515Sgshapiro		(void) memcpy(buf + offset, arg, l1);
211168515Sgshapiro		offset += l1;
212168515Sgshapiro		SM_ASSERT(offset > l1);
213168515Sgshapiro	}
214168515Sgshapiro
215168515Sgshapiro	r = mi_wr_cmd(ctx->ctx_sd, &timeout, cmd, buf, len);
216168515Sgshapiro	free(buf);
217168515Sgshapiro	return r;
218168515Sgshapiro}
219168515Sgshapiro#endif /* 0 */
220168515Sgshapiro
221168515Sgshapiro/*
222168515Sgshapiro**  SEND2 -- construct buffer to send from arguments
223168515Sgshapiro**
224168515Sgshapiro**	Parameters:
225168515Sgshapiro**		ctx -- Opaque context structure
226168515Sgshapiro**		cmd -- command
227168515Sgshapiro**		arg0 -- first argument
228168515Sgshapiro**		argv -- list of arguments (NULL terminated)
229168515Sgshapiro**
230168515Sgshapiro**	Returns:
231168515Sgshapiro**		MI_SUCCESS/MI_FAILURE
232168515Sgshapiro*/
233168515Sgshapiro
234168515Sgshapirostatic int
235168515Sgshapirosend2 __P((SMFICTX *, int cmd, char *, char *));
236168515Sgshapiro
237168515Sgshapirostatic int
238168515Sgshapirosend2(ctx, cmd, arg0, arg1)
239168515Sgshapiro	SMFICTX *ctx;
240168515Sgshapiro	int cmd;
241168515Sgshapiro	char *arg0;
242168515Sgshapiro	char *arg1;
243168515Sgshapiro{
244168515Sgshapiro	size_t len, l0, l1, offset;
245168515Sgshapiro	int r;
246168515Sgshapiro	char *buf;
247168515Sgshapiro	struct timeval timeout;
248168515Sgshapiro
249168515Sgshapiro	if (arg0 == NULL || *arg0 == '\0')
250168515Sgshapiro		return MI_FAILURE;
251168515Sgshapiro	timeout.tv_sec = ctx->ctx_timeout;
252168515Sgshapiro	timeout.tv_usec = 0;
253168515Sgshapiro	l0 = strlen(arg0) + 1;
254168515Sgshapiro	len = l0;
255168515Sgshapiro	if (arg1 != NULL)
256168515Sgshapiro	{
257168515Sgshapiro		l1 = strlen(arg1) + 1;
258168515Sgshapiro		len += l1;
259168515Sgshapiro		SM_ASSERT(len > l1);
260168515Sgshapiro	}
261168515Sgshapiro
262168515Sgshapiro	buf = malloc(len);
263168515Sgshapiro	if (buf == NULL)
264168515Sgshapiro		return MI_FAILURE;
265168515Sgshapiro	(void) memcpy(buf, arg0, l0);
266168515Sgshapiro	offset = l0;
267168515Sgshapiro
268168515Sgshapiro	if (arg1 != NULL)
269168515Sgshapiro	{
270168515Sgshapiro		l1 = strlen(arg1) + 1;
271168515Sgshapiro		SM_ASSERT(offset < len);
272168515Sgshapiro		SM_ASSERT(offset + l1 <= len);
273168515Sgshapiro		(void) memcpy(buf + offset, arg1, l1);
274168515Sgshapiro		offset += l1;
275168515Sgshapiro		SM_ASSERT(offset > l1);
276168515Sgshapiro	}
277168515Sgshapiro
278168515Sgshapiro	r = mi_wr_cmd(ctx->ctx_sd, &timeout, cmd, buf, len);
279168515Sgshapiro	free(buf);
280168515Sgshapiro	return r;
281168515Sgshapiro}
282168515Sgshapiro
283168515Sgshapiro/*
284168515Sgshapiro**  SMFI_CHGFROM -- change enveloper sender ("from") address
285168515Sgshapiro**
286168515Sgshapiro**	Parameters:
287168515Sgshapiro**		ctx -- Opaque context structure
288168515Sgshapiro**		from -- new envelope sender address ("MAIL From")
289168515Sgshapiro**		args -- ESMTP arguments
290168515Sgshapiro**
291168515Sgshapiro**	Returns:
292168515Sgshapiro**		MI_SUCCESS/MI_FAILURE
293168515Sgshapiro*/
294168515Sgshapiro
295168515Sgshapiroint
296168515Sgshapirosmfi_chgfrom(ctx, from, args)
297168515Sgshapiro	SMFICTX *ctx;
298168515Sgshapiro	char *from;
299168515Sgshapiro	char *args;
300168515Sgshapiro{
301168515Sgshapiro	if (from == NULL || *from == '\0')
302168515Sgshapiro		return MI_FAILURE;
303168515Sgshapiro	if (!mi_sendok(ctx, SMFIF_CHGFROM))
304168515Sgshapiro		return MI_FAILURE;
305168515Sgshapiro	return send2(ctx, SMFIR_CHGFROM, from, args);
306168515Sgshapiro}
307168515Sgshapiro
308168515Sgshapiro/*
309168515Sgshapiro**  SMFI_SETSYMLIST -- set list of macros that the MTA should send.
310168515Sgshapiro**
311168515Sgshapiro**	Parameters:
312168515Sgshapiro**		ctx -- Opaque context structure
313168515Sgshapiro**		where -- SMTP stage
314168515Sgshapiro**		macros -- list of macros
315168515Sgshapiro**
316168515Sgshapiro**	Returns:
317168515Sgshapiro**		MI_SUCCESS/MI_FAILURE
318168515Sgshapiro*/
319168515Sgshapiro
320168515Sgshapiroint
321168515Sgshapirosmfi_setsymlist(ctx, where, macros)
322168515Sgshapiro	SMFICTX *ctx;
323168515Sgshapiro	int where;
324168515Sgshapiro	char *macros;
325168515Sgshapiro{
326168515Sgshapiro	SM_ASSERT(ctx != NULL);
327168515Sgshapiro
328168515Sgshapiro	if (macros == NULL || *macros == '\0')
329168515Sgshapiro		return MI_FAILURE;
330168515Sgshapiro	if (where < SMFIM_FIRST || where > SMFIM_LAST)
331168515Sgshapiro		return MI_FAILURE;
332168515Sgshapiro	if (where < 0 || where >= MAX_MACROS_ENTRIES)
333168515Sgshapiro		return MI_FAILURE;
334168515Sgshapiro
335168515Sgshapiro	if (ctx->ctx_mac_list[where] != NULL)
336168515Sgshapiro		return MI_FAILURE;
337168515Sgshapiro
338168515Sgshapiro	ctx->ctx_mac_list[where] = strdup(macros);
339168515Sgshapiro	if (ctx->ctx_mac_list[where] == NULL)
340168515Sgshapiro		return MI_FAILURE;
341168515Sgshapiro
342168515Sgshapiro	return MI_SUCCESS;
343168515Sgshapiro}
344168515Sgshapiro
345168515Sgshapiro/*
346168515Sgshapiro**  SMFI_ADDRCPT_PAR -- send an additional recipient to the MTA
347168515Sgshapiro**
348168515Sgshapiro**	Parameters:
349168515Sgshapiro**		ctx -- Opaque context structure
350168515Sgshapiro**		rcpt -- recipient address
351168515Sgshapiro**		args -- ESMTP arguments
352168515Sgshapiro**
353168515Sgshapiro**	Returns:
354168515Sgshapiro**		MI_SUCCESS/MI_FAILURE
355168515Sgshapiro*/
356168515Sgshapiro
357168515Sgshapiroint
358168515Sgshapirosmfi_addrcpt_par(ctx, rcpt, args)
359168515Sgshapiro	SMFICTX *ctx;
360168515Sgshapiro	char *rcpt;
361168515Sgshapiro	char *args;
362168515Sgshapiro{
363168515Sgshapiro	if (rcpt == NULL || *rcpt == '\0')
364168515Sgshapiro		return MI_FAILURE;
365168515Sgshapiro	if (!mi_sendok(ctx, SMFIF_ADDRCPT_PAR))
366168515Sgshapiro		return MI_FAILURE;
367168515Sgshapiro	return send2(ctx, SMFIR_ADDRCPT_PAR, rcpt, args);
368168515Sgshapiro}
369168515Sgshapiro
370168515Sgshapiro/*
37164562Sgshapiro**  SMFI_ADDRCPT -- send an additional recipient to the MTA
37264562Sgshapiro**
37364562Sgshapiro**	Parameters:
37464562Sgshapiro**		ctx -- Opaque context structure
37564562Sgshapiro**		rcpt -- recipient address
37664562Sgshapiro**
37764562Sgshapiro**	Returns:
37864562Sgshapiro**		MI_SUCCESS/MI_FAILURE
37964562Sgshapiro*/
38064562Sgshapiro
38164562Sgshapiroint
38264562Sgshapirosmfi_addrcpt(ctx, rcpt)
38364562Sgshapiro	SMFICTX *ctx;
38464562Sgshapiro	char *rcpt;
38564562Sgshapiro{
38664562Sgshapiro	size_t len;
38764562Sgshapiro	struct timeval timeout;
38864562Sgshapiro
38964562Sgshapiro	if (rcpt == NULL || *rcpt == '\0')
39064562Sgshapiro		return MI_FAILURE;
39164562Sgshapiro	if (!mi_sendok(ctx, SMFIF_ADDRCPT))
39264562Sgshapiro		return MI_FAILURE;
39364562Sgshapiro	timeout.tv_sec = ctx->ctx_timeout;
39464562Sgshapiro	timeout.tv_usec = 0;
39564562Sgshapiro	len = strlen(rcpt) + 1;
39664562Sgshapiro	return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_ADDRCPT, rcpt, len);
39764562Sgshapiro}
39894334Sgshapiro
39990792Sgshapiro/*
40064562Sgshapiro**  SMFI_DELRCPT -- send a recipient to be removed to the MTA
40164562Sgshapiro**
40264562Sgshapiro**	Parameters:
40364562Sgshapiro**		ctx -- Opaque context structure
40464562Sgshapiro**		rcpt -- recipient address
40564562Sgshapiro**
40664562Sgshapiro**	Returns:
40764562Sgshapiro**		MI_SUCCESS/MI_FAILURE
40864562Sgshapiro*/
40964562Sgshapiro
41064562Sgshapiroint
41164562Sgshapirosmfi_delrcpt(ctx, rcpt)
41264562Sgshapiro	SMFICTX *ctx;
41364562Sgshapiro	char *rcpt;
41464562Sgshapiro{
41564562Sgshapiro	size_t len;
41664562Sgshapiro	struct timeval timeout;
41764562Sgshapiro
41864562Sgshapiro	if (rcpt == NULL || *rcpt == '\0')
41964562Sgshapiro		return MI_FAILURE;
42064562Sgshapiro	if (!mi_sendok(ctx, SMFIF_DELRCPT))
42164562Sgshapiro		return MI_FAILURE;
42264562Sgshapiro	timeout.tv_sec = ctx->ctx_timeout;
42364562Sgshapiro	timeout.tv_usec = 0;
42464562Sgshapiro	len = strlen(rcpt) + 1;
42564562Sgshapiro	return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_DELRCPT, rcpt, len);
42664562Sgshapiro}
42794334Sgshapiro
42890792Sgshapiro/*
42964562Sgshapiro**  SMFI_REPLACEBODY -- send a body chunk to the MTA
43064562Sgshapiro**
43164562Sgshapiro**	Parameters:
43264562Sgshapiro**		ctx -- Opaque context structure
43364562Sgshapiro**		bodyp -- body chunk
43464562Sgshapiro**		bodylen -- length of body chunk
43564562Sgshapiro**
43664562Sgshapiro**	Returns:
43764562Sgshapiro**		MI_SUCCESS/MI_FAILURE
43864562Sgshapiro*/
43964562Sgshapiro
44064562Sgshapiroint
44164562Sgshapirosmfi_replacebody(ctx, bodyp, bodylen)
44264562Sgshapiro	SMFICTX *ctx;
44390792Sgshapiro	unsigned char *bodyp;
44464562Sgshapiro	int bodylen;
44564562Sgshapiro{
44664562Sgshapiro	int len, off, r;
44764562Sgshapiro	struct timeval timeout;
44864562Sgshapiro
44990792Sgshapiro	if (bodylen < 0 ||
45090792Sgshapiro	    (bodyp == NULL && bodylen > 0))
45164562Sgshapiro		return MI_FAILURE;
45264562Sgshapiro	if (!mi_sendok(ctx, SMFIF_CHGBODY))
45364562Sgshapiro		return MI_FAILURE;
45464562Sgshapiro	timeout.tv_sec = ctx->ctx_timeout;
45564562Sgshapiro	timeout.tv_usec = 0;
45664562Sgshapiro
45764562Sgshapiro	/* split body chunk if necessary */
45864562Sgshapiro	off = 0;
459157001Sgshapiro	do
46064562Sgshapiro	{
46164562Sgshapiro		len = (bodylen >= MILTER_CHUNK_SIZE) ? MILTER_CHUNK_SIZE :
46264562Sgshapiro						       bodylen;
46364562Sgshapiro		if ((r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_REPLBODY,
46464562Sgshapiro				(char *) (bodyp + off), len)) != MI_SUCCESS)
46564562Sgshapiro			return r;
46664562Sgshapiro		off += len;
46764562Sgshapiro		bodylen -= len;
468157001Sgshapiro	} while (bodylen > 0);
46964562Sgshapiro	return MI_SUCCESS;
47064562Sgshapiro}
47194334Sgshapiro
47290792Sgshapiro/*
47390792Sgshapiro**  SMFI_QUARANTINE -- quarantine an envelope
47490792Sgshapiro**
47590792Sgshapiro**	Parameters:
47690792Sgshapiro**		ctx -- Opaque context structure
47790792Sgshapiro**		reason -- why?
47890792Sgshapiro**
47990792Sgshapiro**	Returns:
48090792Sgshapiro**		MI_SUCCESS/MI_FAILURE
48190792Sgshapiro*/
48290792Sgshapiro
48390792Sgshapiroint
48490792Sgshapirosmfi_quarantine(ctx, reason)
48590792Sgshapiro	SMFICTX *ctx;
48690792Sgshapiro	char *reason;
48790792Sgshapiro{
48890792Sgshapiro	size_t len;
48990792Sgshapiro	int r;
49090792Sgshapiro	char *buf;
49190792Sgshapiro	struct timeval timeout;
49290792Sgshapiro
49390792Sgshapiro	if (reason == NULL || *reason == '\0')
49490792Sgshapiro		return MI_FAILURE;
49590792Sgshapiro	if (!mi_sendok(ctx, SMFIF_QUARANTINE))
49690792Sgshapiro		return MI_FAILURE;
49790792Sgshapiro	timeout.tv_sec = ctx->ctx_timeout;
49890792Sgshapiro	timeout.tv_usec = 0;
49990792Sgshapiro	len = strlen(reason) + 1;
50090792Sgshapiro	buf = malloc(len);
50190792Sgshapiro	if (buf == NULL)
50290792Sgshapiro		return MI_FAILURE;
50390792Sgshapiro	(void) memcpy(buf, reason, len);
50490792Sgshapiro	r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_QUARANTINE, buf, len);
50590792Sgshapiro	free(buf);
50690792Sgshapiro	return r;
50790792Sgshapiro}
50890792Sgshapiro
50990792Sgshapiro/*
51064562Sgshapiro**  MYISENHSC -- check whether a string contains an enhanced status code
51164562Sgshapiro**
51264562Sgshapiro**	Parameters:
51364562Sgshapiro**		s -- string with possible enhanced status code.
51464562Sgshapiro**		delim -- delim for enhanced status code.
51564562Sgshapiro**
51664562Sgshapiro**	Returns:
51764562Sgshapiro**		0  -- no enhanced status code.
51864562Sgshapiro**		>4 -- length of enhanced status code.
51964562Sgshapiro**
52064562Sgshapiro**	Side Effects:
52164562Sgshapiro**		none.
52264562Sgshapiro*/
52398121Sgshapiro
52464562Sgshapirostatic int
52564562Sgshapiromyisenhsc(s, delim)
52664562Sgshapiro	const char *s;
52764562Sgshapiro	int delim;
52864562Sgshapiro{
52964562Sgshapiro	int l, h;
53064562Sgshapiro
53164562Sgshapiro	if (s == NULL)
53264562Sgshapiro		return 0;
53364562Sgshapiro	if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.'))
53464562Sgshapiro		return 0;
53564562Sgshapiro	h = 0;
53664562Sgshapiro	l = 2;
53764562Sgshapiro	while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
53864562Sgshapiro		++h;
53964562Sgshapiro	if (h == 0 || s[l + h] != '.')
54064562Sgshapiro		return 0;
54164562Sgshapiro	l += h + 1;
54264562Sgshapiro	h = 0;
54364562Sgshapiro	while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
54464562Sgshapiro		++h;
54564562Sgshapiro	if (h == 0 || s[l + h] != delim)
54664562Sgshapiro		return 0;
54764562Sgshapiro	return l + h;
54864562Sgshapiro}
54990792Sgshapiro
55090792Sgshapiro/*
55164562Sgshapiro**  SMFI_SETREPLY -- set the reply code for the next reply to the MTA
55264562Sgshapiro**
55364562Sgshapiro**	Parameters:
55464562Sgshapiro**		ctx -- Opaque context structure
55564562Sgshapiro**		rcode -- The three-digit (RFC 821) SMTP reply code.
55664562Sgshapiro**		xcode -- The extended (RFC 2034) reply code.
55764562Sgshapiro**		message -- The text part of the SMTP reply.
55864562Sgshapiro**
55964562Sgshapiro**	Returns:
56064562Sgshapiro**		MI_SUCCESS/MI_FAILURE
56164562Sgshapiro*/
56264562Sgshapiro
56364562Sgshapiroint
56464562Sgshapirosmfi_setreply(ctx, rcode, xcode, message)
56564562Sgshapiro	SMFICTX *ctx;
56664562Sgshapiro	char *rcode;
56764562Sgshapiro	char *xcode;
56864562Sgshapiro	char *message;
56964562Sgshapiro{
57090792Sgshapiro	size_t len;
57164562Sgshapiro	char *buf;
57264562Sgshapiro
57364562Sgshapiro	if (rcode == NULL || ctx == NULL)
57464562Sgshapiro		return MI_FAILURE;
57590792Sgshapiro
57690792Sgshapiro	/* ### <sp> \0 */
57790792Sgshapiro	len = strlen(rcode) + 2;
57890792Sgshapiro	if (len != 5)
57964562Sgshapiro		return MI_FAILURE;
58064562Sgshapiro	if ((rcode[0] != '4' && rcode[0] != '5') ||
58164562Sgshapiro	    !isascii(rcode[1]) || !isdigit(rcode[1]) ||
58264562Sgshapiro	    !isascii(rcode[2]) || !isdigit(rcode[2]))
58364562Sgshapiro		return MI_FAILURE;
58490792Sgshapiro	if (xcode != NULL)
58590792Sgshapiro	{
58690792Sgshapiro		if (!myisenhsc(xcode, '\0'))
58790792Sgshapiro			return MI_FAILURE;
58890792Sgshapiro		len += strlen(xcode) + 1;
58990792Sgshapiro	}
59090792Sgshapiro	if (message != NULL)
59190792Sgshapiro	{
59290792Sgshapiro		size_t ml;
59390792Sgshapiro
59490792Sgshapiro		/* XXX check also for unprintable chars? */
59590792Sgshapiro		if (strpbrk(message, "\r\n") != NULL)
59690792Sgshapiro			return MI_FAILURE;
59790792Sgshapiro		ml = strlen(message);
59890792Sgshapiro		if (ml > MAXREPLYLEN)
59990792Sgshapiro			return MI_FAILURE;
60090792Sgshapiro		len += ml + 1;
60190792Sgshapiro	}
60290792Sgshapiro	buf = malloc(len);
60390792Sgshapiro	if (buf == NULL)
60490792Sgshapiro		return MI_FAILURE;		/* oops */
60590792Sgshapiro	(void) sm_strlcpy(buf, rcode, len);
60690792Sgshapiro	(void) sm_strlcat(buf, " ", len);
60790792Sgshapiro	if (xcode != NULL)
60890792Sgshapiro		(void) sm_strlcat(buf, xcode, len);
60990792Sgshapiro	if (message != NULL)
61090792Sgshapiro	{
61190792Sgshapiro		if (xcode != NULL)
61290792Sgshapiro			(void) sm_strlcat(buf, " ", len);
61390792Sgshapiro		(void) sm_strlcat(buf, message, len);
61490792Sgshapiro	}
61590792Sgshapiro	if (ctx->ctx_reply != NULL)
61690792Sgshapiro		free(ctx->ctx_reply);
61790792Sgshapiro	ctx->ctx_reply = buf;
61890792Sgshapiro	return MI_SUCCESS;
61990792Sgshapiro}
62090792Sgshapiro
62190792Sgshapiro/*
62290792Sgshapiro**  SMFI_SETMLREPLY -- set multiline reply code for the next reply to the MTA
62390792Sgshapiro**
62490792Sgshapiro**	Parameters:
62590792Sgshapiro**		ctx -- Opaque context structure
62690792Sgshapiro**		rcode -- The three-digit (RFC 821) SMTP reply code.
62790792Sgshapiro**		xcode -- The extended (RFC 2034) reply code.
62890792Sgshapiro**		txt, ... -- The text part of the SMTP reply,
62990792Sgshapiro**			MUST be terminated with NULL.
63090792Sgshapiro**
63190792Sgshapiro**	Returns:
63290792Sgshapiro**		MI_SUCCESS/MI_FAILURE
63390792Sgshapiro*/
63490792Sgshapiro
63590792Sgshapiroint
63690792Sgshapiro#if SM_VA_STD
63790792Sgshapirosmfi_setmlreply(SMFICTX *ctx, const char *rcode, const char *xcode, ...)
63890792Sgshapiro#else /* SM_VA_STD */
63990792Sgshapirosmfi_setmlreply(ctx, rcode, xcode, va_alist)
64090792Sgshapiro	SMFICTX *ctx;
64190792Sgshapiro	const char *rcode;
64290792Sgshapiro	const char *xcode;
64390792Sgshapiro	va_dcl
64490792Sgshapiro#endif /* SM_VA_STD */
64590792Sgshapiro{
64690792Sgshapiro	size_t len;
64790792Sgshapiro	size_t rlen;
64890792Sgshapiro	int args;
64990792Sgshapiro	char *buf, *txt;
65090792Sgshapiro	const char *xc;
65190792Sgshapiro	char repl[16];
65290792Sgshapiro	SM_VA_LOCAL_DECL
65390792Sgshapiro
65490792Sgshapiro	if (rcode == NULL || ctx == NULL)
65564562Sgshapiro		return MI_FAILURE;
65690792Sgshapiro
65790792Sgshapiro	/* ### <sp> */
65890792Sgshapiro	len = strlen(rcode) + 1;
65990792Sgshapiro	if (len != 4)
66090792Sgshapiro		return MI_FAILURE;
66190792Sgshapiro	if ((rcode[0] != '4' && rcode[0] != '5') ||
66290792Sgshapiro	    !isascii(rcode[1]) || !isdigit(rcode[1]) ||
66390792Sgshapiro	    !isascii(rcode[2]) || !isdigit(rcode[2]))
66490792Sgshapiro		return MI_FAILURE;
66590792Sgshapiro	if (xcode != NULL)
66690792Sgshapiro	{
66790792Sgshapiro		if (!myisenhsc(xcode, '\0'))
66890792Sgshapiro			return MI_FAILURE;
66990792Sgshapiro		xc = xcode;
67090792Sgshapiro	}
67190792Sgshapiro	else
67290792Sgshapiro	{
67390792Sgshapiro		if (rcode[0] == '4')
67490792Sgshapiro			xc = "4.0.0";
67590792Sgshapiro		else
67690792Sgshapiro			xc = "5.0.0";
67790792Sgshapiro	}
67890792Sgshapiro
67990792Sgshapiro	/* add trailing space */
68090792Sgshapiro	len += strlen(xc) + 1;
68190792Sgshapiro	rlen = len;
68290792Sgshapiro	args = 0;
68390792Sgshapiro	SM_VA_START(ap, xcode);
68490792Sgshapiro	while ((txt = SM_VA_ARG(ap, char *)) != NULL)
68590792Sgshapiro	{
68690792Sgshapiro		size_t tl;
68790792Sgshapiro
68890792Sgshapiro		tl = strlen(txt);
68990792Sgshapiro		if (tl > MAXREPLYLEN)
69094334Sgshapiro			break;
69190792Sgshapiro
69290792Sgshapiro		/* this text, reply codes, \r\n */
69390792Sgshapiro		len += tl + 2 + rlen;
69490792Sgshapiro		if (++args > MAXREPLIES)
69594334Sgshapiro			break;
69690792Sgshapiro
69790792Sgshapiro		/* XXX check also for unprintable chars? */
69890792Sgshapiro		if (strpbrk(txt, "\r\n") != NULL)
69994334Sgshapiro			break;
70090792Sgshapiro	}
70190792Sgshapiro	SM_VA_END(ap);
70294334Sgshapiro	if (txt != NULL)
70394334Sgshapiro		return MI_FAILURE;
70490792Sgshapiro
70590792Sgshapiro	/* trailing '\0' */
70690792Sgshapiro	++len;
70764562Sgshapiro	buf = malloc(len);
70864562Sgshapiro	if (buf == NULL)
70964562Sgshapiro		return MI_FAILURE;		/* oops */
71090792Sgshapiro	(void) sm_strlcpyn(buf, len, 3, rcode, args == 1 ? " " : "-", xc);
71190792Sgshapiro	(void) sm_strlcpyn(repl, sizeof repl, 4, rcode, args == 1 ? " " : "-",
71290792Sgshapiro			   xc, " ");
71390792Sgshapiro	SM_VA_START(ap, xcode);
71490792Sgshapiro	txt = SM_VA_ARG(ap, char *);
71590792Sgshapiro	if (txt != NULL)
71690792Sgshapiro	{
71790792Sgshapiro		(void) sm_strlcat2(buf, " ", txt, len);
71890792Sgshapiro		while ((txt = SM_VA_ARG(ap, char *)) != NULL)
71990792Sgshapiro		{
72090792Sgshapiro			if (--args <= 1)
72190792Sgshapiro				repl[3] = ' ';
72290792Sgshapiro			(void) sm_strlcat2(buf, "\r\n", repl, len);
72390792Sgshapiro			(void) sm_strlcat(buf, txt, len);
72490792Sgshapiro		}
72590792Sgshapiro	}
72664562Sgshapiro	if (ctx->ctx_reply != NULL)
72764562Sgshapiro		free(ctx->ctx_reply);
72864562Sgshapiro	ctx->ctx_reply = buf;
72990792Sgshapiro	SM_VA_END(ap);
73064562Sgshapiro	return MI_SUCCESS;
73164562Sgshapiro}
73290792Sgshapiro
73390792Sgshapiro/*
73464562Sgshapiro**  SMFI_SETPRIV -- set private data
73564562Sgshapiro**
73664562Sgshapiro**	Parameters:
73764562Sgshapiro**		ctx -- Opaque context structure
73864562Sgshapiro**		privatedata -- pointer to private data
73964562Sgshapiro**
74064562Sgshapiro**	Returns:
74164562Sgshapiro**		MI_SUCCESS/MI_FAILURE
74264562Sgshapiro*/
74364562Sgshapiro
74464562Sgshapiroint
74564562Sgshapirosmfi_setpriv(ctx, privatedata)
74664562Sgshapiro	SMFICTX *ctx;
74764562Sgshapiro	void *privatedata;
74864562Sgshapiro{
74964562Sgshapiro	if (ctx == NULL)
75064562Sgshapiro		return MI_FAILURE;
75164562Sgshapiro	ctx->ctx_privdata = privatedata;
75264562Sgshapiro	return MI_SUCCESS;
75364562Sgshapiro}
75494334Sgshapiro
75590792Sgshapiro/*
75664562Sgshapiro**  SMFI_GETPRIV -- get private data
75764562Sgshapiro**
75864562Sgshapiro**	Parameters:
75964562Sgshapiro**		ctx -- Opaque context structure
76064562Sgshapiro**
76164562Sgshapiro**	Returns:
76264562Sgshapiro**		pointer to private data
76364562Sgshapiro*/
76464562Sgshapiro
76564562Sgshapirovoid *
76664562Sgshapirosmfi_getpriv(ctx)
76764562Sgshapiro	SMFICTX *ctx;
76864562Sgshapiro{
76964562Sgshapiro	if (ctx == NULL)
77064562Sgshapiro		return NULL;
77164562Sgshapiro	return ctx->ctx_privdata;
77264562Sgshapiro}
77394334Sgshapiro
77490792Sgshapiro/*
77564562Sgshapiro**  SMFI_GETSYMVAL -- get the value of a macro
77664562Sgshapiro**
77764562Sgshapiro**	See explanation in mfapi.h about layout of the structures.
77864562Sgshapiro**
77964562Sgshapiro**	Parameters:
78064562Sgshapiro**		ctx -- Opaque context structure
78164562Sgshapiro**		symname -- name of macro
78264562Sgshapiro**
78364562Sgshapiro**	Returns:
78464562Sgshapiro**		value of macro (NULL in case of failure)
78564562Sgshapiro*/
78664562Sgshapiro
78764562Sgshapirochar *
78864562Sgshapirosmfi_getsymval(ctx, symname)
78964562Sgshapiro	SMFICTX *ctx;
79064562Sgshapiro	char *symname;
79164562Sgshapiro{
79264562Sgshapiro	int i;
79364562Sgshapiro	char **s;
79464562Sgshapiro	char one[2];
79564562Sgshapiro	char braces[4];
79664562Sgshapiro
79764562Sgshapiro	if (ctx == NULL || symname == NULL || *symname == '\0')
79864562Sgshapiro		return NULL;
79964562Sgshapiro
80064562Sgshapiro	if (strlen(symname) == 3 && symname[0] == '{' && symname[2] == '}')
80164562Sgshapiro	{
80264562Sgshapiro		one[0] = symname[1];
80364562Sgshapiro		one[1] = '\0';
80464562Sgshapiro	}
80564562Sgshapiro	else
80664562Sgshapiro		one[0] = '\0';
80764562Sgshapiro	if (strlen(symname) == 1)
80864562Sgshapiro	{
80964562Sgshapiro		braces[0] = '{';
81064562Sgshapiro		braces[1] = *symname;
81164562Sgshapiro		braces[2] = '}';
81264562Sgshapiro		braces[3] = '\0';
81364562Sgshapiro	}
81464562Sgshapiro	else
81564562Sgshapiro		braces[0] = '\0';
81664562Sgshapiro
81764562Sgshapiro	/* search backwards through the macro array */
81864562Sgshapiro	for (i = MAX_MACROS_ENTRIES - 1 ; i >= 0; --i)
81964562Sgshapiro	{
82064562Sgshapiro		if ((s = ctx->ctx_mac_ptr[i]) == NULL ||
82164562Sgshapiro		    ctx->ctx_mac_buf[i] == NULL)
82264562Sgshapiro			continue;
82364562Sgshapiro		while (s != NULL && *s != NULL)
82464562Sgshapiro		{
82564562Sgshapiro			if (strcmp(*s, symname) == 0)
82664562Sgshapiro				return *++s;
82764562Sgshapiro			if (one[0] != '\0' && strcmp(*s, one) == 0)
82864562Sgshapiro				return *++s;
82964562Sgshapiro			if (braces[0] != '\0' && strcmp(*s, braces) == 0)
83064562Sgshapiro				return *++s;
83164562Sgshapiro			++s;	/* skip over macro value */
83264562Sgshapiro			++s;	/* points to next macro name */
83364562Sgshapiro		}
83464562Sgshapiro	}
83564562Sgshapiro	return NULL;
83664562Sgshapiro}
83794334Sgshapiro
83894334Sgshapiro/*
83994334Sgshapiro**  SMFI_PROGRESS -- send "progress" message to the MTA to prevent premature
84094334Sgshapiro**		     timeouts during long milter-side operations
84194334Sgshapiro**
84294334Sgshapiro**	Parameters:
84394334Sgshapiro**		ctx -- Opaque context structure
84494334Sgshapiro**
84594334Sgshapiro**	Return value:
84694334Sgshapiro**		MI_SUCCESS/MI_FAILURE
84794334Sgshapiro*/
84894334Sgshapiro
84994334Sgshapiroint
85094334Sgshapirosmfi_progress(ctx)
85194334Sgshapiro	SMFICTX *ctx;
85294334Sgshapiro{
85394334Sgshapiro	struct timeval timeout;
85494334Sgshapiro
85594334Sgshapiro	if (ctx == NULL)
85694334Sgshapiro		return MI_FAILURE;
85794334Sgshapiro
85894334Sgshapiro	timeout.tv_sec = ctx->ctx_timeout;
85994334Sgshapiro	timeout.tv_usec = 0;
86094334Sgshapiro
86194334Sgshapiro	return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_PROGRESS, NULL, 0);
86294334Sgshapiro}
863168515Sgshapiro
864168515Sgshapiro/*
865168515Sgshapiro**  SMFI_VERSION -- return (runtime) version of libmilter
866168515Sgshapiro**
867168515Sgshapiro**	Parameters:
868168515Sgshapiro**		major -- (pointer to) major version
869168515Sgshapiro**		minor -- (pointer to) minor version
870168515Sgshapiro**		patchlevel -- (pointer to) patchlevel version
871168515Sgshapiro**
872168515Sgshapiro**	Return value:
873168515Sgshapiro**		MI_SUCCESS
874168515Sgshapiro*/
875168515Sgshapiro
876168515Sgshapiroint
877168515Sgshapirosmfi_version(major, minor, patchlevel)
878168515Sgshapiro	unsigned int *major;
879168515Sgshapiro	unsigned int *minor;
880168515Sgshapiro	unsigned int *patchlevel;
881168515Sgshapiro{
882168515Sgshapiro	if (major != NULL)
883168515Sgshapiro		*major = SM_LM_VRS_MAJOR(SMFI_VERSION);
884168515Sgshapiro	if (minor != NULL)
885168515Sgshapiro		*minor = SM_LM_VRS_MINOR(SMFI_VERSION);
886168515Sgshapiro	if (patchlevel != NULL)
887173340Sgshapiro		*patchlevel = SM_LM_VRS_PLVL(SMFI_VERSION);
888168515Sgshapiro	return MI_SUCCESS;
889168515Sgshapiro}
890