1/*	$NetBSD$	*/
2
3/*++
4/* NAME
5/*	milter_macros
6/* SUMMARY
7/*	manipulate MILTER_MACROS structures
8/* SYNOPSIS
9/*	#include <milter.h>
10/*
11/*	MILTER_MACROS *milter_macros_create(conn_macros, helo_macros,
12/*					mail_macros, rcpt_macros,
13/*					data_macros, eoh_macros,
14/*					eod_macros, unk_macros)
15/*	const char *conn_macros;
16/*	const char *helo_macros;
17/*	const char *mail_macros;
18/*	const char *rcpt_macrps;
19/*	const char *data_macros;
20/*	const char *eoh_macros;
21/*	const char *eod_macros;
22/*	const char *unk_macros;
23/*
24/*	MILTER_MACROS *milter_macros_alloc(init_mode)
25/*	int	init_mode;
26/*
27/*	void	milter_macros_free(mp)
28/*	MILTER_MACROS *mp;
29/*
30/*	int     milter_macros_print(print_fn, stream, flags, ptr)
31/*	ATTR_PRINT_MASTER_FN print_fn;
32/*	VSTREAM *stream;
33/*	int	flags;
34/*	void	*ptr;
35/*
36/*	int	milter_macros_scan(scan_fn, fp, flags, ptr)
37/*	ATTR_SCAN_MASTER_FN scan_fn;
38/*	VSTREAM	*fp;
39/*	int	flags;
40/*	void	*ptr;
41/* DESCRIPTION
42/*	Sendmail mail filter (Milter) applications receive sets of
43/*	macro name=value pairs with each SMTP or content event.
44/*	In Postfix, these macro names are stored in MILTER_MACROS
45/*	structures, as one list for each event type. By default,
46/*	the same structure is shared by all Milter applications;
47/*	it is initialized with information from main.cf. With
48/*	Sendmail 8.14 a Milter can override one or more lists of
49/*	macro names. Postfix implements this by giving the Milter
50/*	its own MILTER_MACROS structure and by storing the per-Milter
51/*	information there.
52/*
53/*	This module maintains per-event macro name lists as
54/*	mystrdup()'ed values. The user is explicitly allowed to
55/*	update these values directly, as long as the result is
56/*	compatible with mystrdup().
57/*
58/*	milter_macros_create() creates a MILTER_MACROS structure
59/*	and initializes it with copies of its string arguments.
60/*	Null pointers are not valid as input.
61/*
62/*	milter_macros_alloc() creates am empty MILTER_MACROS structure
63/*	that is initialized according to its init_mode argument.
64/* .IP MILTER_MACROS_ALLOC_ZERO
65/*	Initialize all structure members as null pointers. This
66/*	mode must be used with milter_macros_scan(), because that
67/*	function blindly overwrites all structure members.  No other
68/*	function except milter_macros_free() allows structure members
69/*	with null pointer values.
70/* .IP MILTER_MACROS_ALLOC_EMPTY
71/*	Initialize all structure members with mystrdup(""). This
72/*	is not as expensive as it appears to be.
73/* .PP
74/*	milter_macros_free() destroys a MILTER_MACROS structure and
75/*	frees any strings referenced by it.
76/*
77/*	milter_macros_print() writes the contents of a MILTER_MACROS
78/*	structure to the named stream using the specified attribute
79/*	print routine.  milter_macros_print() is meant to be passed
80/*	as a call-back to attr_print*(), thusly:
81/*
82/*	ATTR_TYPE_FUNC, milter_macros_print, (void *) macros,
83/*
84/*	milter_macros_scan() reads a MILTER_MACROS structure from
85/*	the named stream using the specified attribute scan routine.
86/*	No attempt is made to free the memory of existing structure
87/*	members.  milter_macros_scan() is meant to be passed as a
88/*	call-back to attr_scan*(), thusly:
89/*
90/*	ATTR_TYPE_FUNC, milter_macros_scan, (void *) macros,
91/* DIAGNOSTICS
92/*	Fatal: out of memory.
93/* LICENSE
94/* .ad
95/* .fi
96/*	The Secure Mailer license must be distributed with this
97/*	software.
98/* AUTHOR(S)
99/*	Wietse Venema IBM T.J. Watson Research P.O. Box 704 Yorktown
100/*	Heights, NY 10598, USA
101/*--*/
102
103/* System library. */
104
105#include <sys_defs.h>
106
107/* Utility library. */
108
109#include <msg.h>
110#include <attr.h>
111#include <mymalloc.h>
112#include <vstring.h>
113
114/* Global library. */
115
116#include <mail_proto.h>
117#include <milter.h>
118
119 /*
120  * Ad-hoc protocol to send/receive milter macro name lists.
121  */
122#define MAIL_ATTR_MILT_MAC_CONN	"conn_macros"
123#define MAIL_ATTR_MILT_MAC_HELO	"helo_macros"
124#define MAIL_ATTR_MILT_MAC_MAIL	"mail_macros"
125#define MAIL_ATTR_MILT_MAC_RCPT	"rcpt_macros"
126#define MAIL_ATTR_MILT_MAC_DATA	"data_macros"
127#define MAIL_ATTR_MILT_MAC_EOH	"eoh_macros"
128#define MAIL_ATTR_MILT_MAC_EOD	"eod_macros"
129#define MAIL_ATTR_MILT_MAC_UNK	"unk_macros"
130
131/* milter_macros_print - write macros structure to stream */
132
133int     milter_macros_print(ATTR_PRINT_MASTER_FN print_fn, VSTREAM *fp,
134			            int flags, void *ptr)
135{
136    MILTER_MACROS *mp = (MILTER_MACROS *) ptr;
137    int     ret;
138
139    /*
140     * The attribute order does not matter, except that it must be the same
141     * as in the milter_macros_scan() function.
142     */
143    ret = print_fn(fp, flags | ATTR_FLAG_MORE,
144		   ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_CONN, mp->conn_macros,
145		   ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_HELO, mp->helo_macros,
146		   ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_MAIL, mp->mail_macros,
147		   ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_RCPT, mp->rcpt_macros,
148		   ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_DATA, mp->data_macros,
149		   ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_EOH, mp->eoh_macros,
150		   ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_EOD, mp->eod_macros,
151		   ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_UNK, mp->unk_macros,
152		   ATTR_TYPE_END);
153    return (ret);
154}
155
156/* milter_macros_scan - receive macros structure from stream */
157
158int     milter_macros_scan(ATTR_SCAN_MASTER_FN scan_fn, VSTREAM *fp,
159			           int flags, void *ptr)
160{
161    MILTER_MACROS *mp = (MILTER_MACROS *) ptr;
162    int     ret;
163
164    /*
165     * We could simplify this by moving memory allocation into attr_scan*().
166     */
167    VSTRING *conn_macros = vstring_alloc(10);
168    VSTRING *helo_macros = vstring_alloc(10);
169    VSTRING *mail_macros = vstring_alloc(10);
170    VSTRING *rcpt_macros = vstring_alloc(10);
171    VSTRING *data_macros = vstring_alloc(10);
172    VSTRING *eoh_macros = vstring_alloc(10);
173    VSTRING *eod_macros = vstring_alloc(10);
174    VSTRING *unk_macros = vstring_alloc(10);
175
176    /*
177     * The attribute order does not matter, except that it must be the same
178     * as in the milter_macros_print() function.
179     */
180    ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
181		  ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_CONN, conn_macros,
182		  ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_HELO, helo_macros,
183		  ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_MAIL, mail_macros,
184		  ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_RCPT, rcpt_macros,
185		  ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_DATA, data_macros,
186		  ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_EOH, eoh_macros,
187		  ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_EOD, eod_macros,
188		  ATTR_TYPE_STR, MAIL_ATTR_MILT_MAC_UNK, unk_macros,
189		  ATTR_TYPE_END);
190
191    /*
192     * Don't optimize for error.
193     */
194    mp->conn_macros = vstring_export(conn_macros);
195    mp->helo_macros = vstring_export(helo_macros);
196    mp->mail_macros = vstring_export(mail_macros);
197    mp->rcpt_macros = vstring_export(rcpt_macros);
198    mp->data_macros = vstring_export(data_macros);
199    mp->eoh_macros = vstring_export(eoh_macros);
200    mp->eod_macros = vstring_export(eod_macros);
201    mp->unk_macros = vstring_export(unk_macros);
202
203    return (ret == 8 ? 1 : -1);
204}
205
206/* milter_macros_create - create and initialize macros structure */
207
208MILTER_MACROS *milter_macros_create(const char *conn_macros,
209				            const char *helo_macros,
210				            const char *mail_macros,
211				            const char *rcpt_macros,
212				            const char *data_macros,
213				            const char *eoh_macros,
214				            const char *eod_macros,
215				            const char *unk_macros)
216{
217    MILTER_MACROS *mp;
218
219    mp = (MILTER_MACROS *) mymalloc(sizeof(*mp));
220    mp->conn_macros = mystrdup(conn_macros);
221    mp->helo_macros = mystrdup(helo_macros);
222    mp->mail_macros = mystrdup(mail_macros);
223    mp->rcpt_macros = mystrdup(rcpt_macros);
224    mp->data_macros = mystrdup(data_macros);
225    mp->eoh_macros = mystrdup(eoh_macros);
226    mp->eod_macros = mystrdup(eod_macros);
227    mp->unk_macros = mystrdup(unk_macros);
228
229    return (mp);
230}
231
232/* milter_macros_alloc - allocate macros structure with simple initialization */
233
234MILTER_MACROS *milter_macros_alloc(int mode)
235{
236    MILTER_MACROS *mp;
237
238    /*
239     * This macro was originally in milter.h, but no-one else needed it.
240     */
241#define milter_macros_init(mp, expr) do { \
242	MILTER_MACROS *__mp = (mp); \
243	char *__expr = (expr); \
244	__mp->conn_macros = __expr; \
245	__mp->helo_macros = __expr; \
246	__mp->mail_macros = __expr; \
247	__mp->rcpt_macros = __expr; \
248	__mp->data_macros = __expr; \
249	__mp->eoh_macros = __expr; \
250	__mp->eod_macros = __expr; \
251	__mp->unk_macros = __expr; \
252    } while (0)
253
254    mp = (MILTER_MACROS *) mymalloc(sizeof(*mp));
255    switch (mode) {
256    case MILTER_MACROS_ALLOC_ZERO:
257	milter_macros_init(mp, 0);
258	break;
259    case MILTER_MACROS_ALLOC_EMPTY:
260	milter_macros_init(mp, mystrdup(""));
261	break;
262    default:
263	msg_panic("milter_macros_alloc: unknown mode %d", mode);
264    }
265    return (mp);
266}
267
268/* milter_macros_free - destroy memory for MILTER_MACROS structure */
269
270void    milter_macros_free(MILTER_MACROS *mp)
271{
272
273    /*
274     * This macro was originally in milter.h, but no-one else needed it.
275     */
276#define milter_macros_wipe(mp) do { \
277	MILTER_MACROS *__mp = mp; \
278	if (__mp->conn_macros) \
279	    myfree(__mp->conn_macros); \
280	if (__mp->helo_macros) \
281	    myfree(__mp->helo_macros); \
282	if (__mp->mail_macros) \
283	    myfree(__mp->mail_macros); \
284	if (__mp->rcpt_macros) \
285	    myfree(__mp->rcpt_macros); \
286	if (__mp->data_macros) \
287	    myfree(__mp->data_macros); \
288	if (__mp->eoh_macros) \
289	    myfree(__mp->eoh_macros); \
290	if (__mp->eod_macros) \
291	    myfree(__mp->eod_macros); \
292	if (__mp->unk_macros) \
293	    myfree(__mp->unk_macros); \
294    } while (0)
295
296    milter_macros_wipe(mp);
297    myfree((char *) mp);
298}
299