1 /*        $NetBSD: milter_macros.c,v 1.3 2022/10/08 16:12:46 christos Exp $     */
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_COMMON_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_COMMON_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 /*        SEND_ATTR_FUNC(milter_macros_print, (const 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 /*        RECV_ATTR_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
100 /*        IBM T.J. Watson Research
101 /*        P.O. Box 704
102 /*        Yorktown Heights, NY 10598, USA
103 /*
104 /*        Wietse Venema
105 /*        Google, Inc.
106 /*        111 8th Avenue
107 /*        New York, NY 10011, USA
108 /*--*/
109 
110 /* System library. */
111 
112 #include <sys_defs.h>
113 
114 /* Utility library. */
115 
116 #include <msg.h>
117 #include <attr.h>
118 #include <mymalloc.h>
119 #include <vstring.h>
120 
121 /* Global library. */
122 
123 #include <mail_proto.h>
124 #include <milter.h>
125 
126  /*
127   * Ad-hoc protocol to send/receive milter macro name lists.
128   */
129 #define MAIL_ATTR_MILT_MAC_CONN         "conn_macros"
130 #define MAIL_ATTR_MILT_MAC_HELO         "helo_macros"
131 #define MAIL_ATTR_MILT_MAC_MAIL         "mail_macros"
132 #define MAIL_ATTR_MILT_MAC_RCPT         "rcpt_macros"
133 #define MAIL_ATTR_MILT_MAC_DATA         "data_macros"
134 #define MAIL_ATTR_MILT_MAC_EOH          "eoh_macros"
135 #define MAIL_ATTR_MILT_MAC_EOD          "eod_macros"
136 #define MAIL_ATTR_MILT_MAC_UNK          "unk_macros"
137 
138 /* milter_macros_print - write macros structure to stream */
139 
milter_macros_print(ATTR_PRINT_COMMON_FN print_fn,VSTREAM * fp,int flags,const void * ptr)140 int     milter_macros_print(ATTR_PRINT_COMMON_FN print_fn, VSTREAM *fp,
141                                           int flags, const void *ptr)
142 {
143     MILTER_MACROS *mp = (MILTER_MACROS *) ptr;
144     int     ret;
145 
146     /*
147      * The attribute order does not matter, except that it must be the same
148      * as in the milter_macros_scan() function.
149      */
150     ret = print_fn(fp, flags | ATTR_FLAG_MORE,
151                        SEND_ATTR_STR(MAIL_ATTR_MILT_MAC_CONN, mp->conn_macros),
152                        SEND_ATTR_STR(MAIL_ATTR_MILT_MAC_HELO, mp->helo_macros),
153                        SEND_ATTR_STR(MAIL_ATTR_MILT_MAC_MAIL, mp->mail_macros),
154                        SEND_ATTR_STR(MAIL_ATTR_MILT_MAC_RCPT, mp->rcpt_macros),
155                        SEND_ATTR_STR(MAIL_ATTR_MILT_MAC_DATA, mp->data_macros),
156                        SEND_ATTR_STR(MAIL_ATTR_MILT_MAC_EOH, mp->eoh_macros),
157                        SEND_ATTR_STR(MAIL_ATTR_MILT_MAC_EOD, mp->eod_macros),
158                        SEND_ATTR_STR(MAIL_ATTR_MILT_MAC_UNK, mp->unk_macros),
159                        ATTR_TYPE_END);
160     return (ret);
161 }
162 
163 /* milter_macros_scan - receive macros structure from stream */
164 
milter_macros_scan(ATTR_SCAN_COMMON_FN scan_fn,VSTREAM * fp,int flags,void * ptr)165 int     milter_macros_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
166                                          int flags, void *ptr)
167 {
168     MILTER_MACROS *mp = (MILTER_MACROS *) ptr;
169     int     ret;
170 
171     /*
172      * We could simplify this by moving memory allocation into attr_scan*().
173      */
174     VSTRING *conn_macros = vstring_alloc(10);
175     VSTRING *helo_macros = vstring_alloc(10);
176     VSTRING *mail_macros = vstring_alloc(10);
177     VSTRING *rcpt_macros = vstring_alloc(10);
178     VSTRING *data_macros = vstring_alloc(10);
179     VSTRING *eoh_macros = vstring_alloc(10);
180     VSTRING *eod_macros = vstring_alloc(10);
181     VSTRING *unk_macros = vstring_alloc(10);
182 
183     /*
184      * The attribute order does not matter, except that it must be the same
185      * as in the milter_macros_print() function.
186      */
187     ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
188                       RECV_ATTR_STR(MAIL_ATTR_MILT_MAC_CONN, conn_macros),
189                       RECV_ATTR_STR(MAIL_ATTR_MILT_MAC_HELO, helo_macros),
190                       RECV_ATTR_STR(MAIL_ATTR_MILT_MAC_MAIL, mail_macros),
191                       RECV_ATTR_STR(MAIL_ATTR_MILT_MAC_RCPT, rcpt_macros),
192                       RECV_ATTR_STR(MAIL_ATTR_MILT_MAC_DATA, data_macros),
193                       RECV_ATTR_STR(MAIL_ATTR_MILT_MAC_EOH, eoh_macros),
194                       RECV_ATTR_STR(MAIL_ATTR_MILT_MAC_EOD, eod_macros),
195                       RECV_ATTR_STR(MAIL_ATTR_MILT_MAC_UNK, unk_macros),
196                       ATTR_TYPE_END);
197 
198     /*
199      * Don't optimize for error.
200      */
201     mp->conn_macros = vstring_export(conn_macros);
202     mp->helo_macros = vstring_export(helo_macros);
203     mp->mail_macros = vstring_export(mail_macros);
204     mp->rcpt_macros = vstring_export(rcpt_macros);
205     mp->data_macros = vstring_export(data_macros);
206     mp->eoh_macros = vstring_export(eoh_macros);
207     mp->eod_macros = vstring_export(eod_macros);
208     mp->unk_macros = vstring_export(unk_macros);
209 
210     return (ret == 8 ? 1 : -1);
211 }
212 
213 /* milter_macros_create - create and initialize macros structure */
214 
milter_macros_create(const char * conn_macros,const char * helo_macros,const char * mail_macros,const char * rcpt_macros,const char * data_macros,const char * eoh_macros,const char * eod_macros,const char * unk_macros)215 MILTER_MACROS *milter_macros_create(const char *conn_macros,
216                                                     const char *helo_macros,
217                                                     const char *mail_macros,
218                                                     const char *rcpt_macros,
219                                                     const char *data_macros,
220                                                     const char *eoh_macros,
221                                                     const char *eod_macros,
222                                                     const char *unk_macros)
223 {
224     MILTER_MACROS *mp;
225 
226     mp = (MILTER_MACROS *) mymalloc(sizeof(*mp));
227     mp->conn_macros = mystrdup(conn_macros);
228     mp->helo_macros = mystrdup(helo_macros);
229     mp->mail_macros = mystrdup(mail_macros);
230     mp->rcpt_macros = mystrdup(rcpt_macros);
231     mp->data_macros = mystrdup(data_macros);
232     mp->eoh_macros = mystrdup(eoh_macros);
233     mp->eod_macros = mystrdup(eod_macros);
234     mp->unk_macros = mystrdup(unk_macros);
235 
236     return (mp);
237 }
238 
239 /* milter_macros_alloc - allocate macros structure with simple initialization */
240 
milter_macros_alloc(int mode)241 MILTER_MACROS *milter_macros_alloc(int mode)
242 {
243     MILTER_MACROS *mp;
244 
245     /*
246      * This macro was originally in milter.h, but no-one else needed it.
247      */
248 #define milter_macros_init(mp, expr) do { \
249           MILTER_MACROS *__mp = (mp); \
250           char *__expr = (expr); \
251           __mp->conn_macros = __expr; \
252           __mp->helo_macros = __expr; \
253           __mp->mail_macros = __expr; \
254           __mp->rcpt_macros = __expr; \
255           __mp->data_macros = __expr; \
256           __mp->eoh_macros = __expr; \
257           __mp->eod_macros = __expr; \
258           __mp->unk_macros = __expr; \
259     } while (0)
260 
261     mp = (MILTER_MACROS *) mymalloc(sizeof(*mp));
262     switch (mode) {
263     case MILTER_MACROS_ALLOC_ZERO:
264           milter_macros_init(mp, 0);
265           break;
266     case MILTER_MACROS_ALLOC_EMPTY:
267           milter_macros_init(mp, mystrdup(""));
268           break;
269     default:
270           msg_panic("milter_macros_alloc: unknown mode %d", mode);
271     }
272     return (mp);
273 }
274 
275 /* milter_macros_free - destroy memory for MILTER_MACROS structure */
276 
milter_macros_free(MILTER_MACROS * mp)277 void    milter_macros_free(MILTER_MACROS *mp)
278 {
279 
280     /*
281      * This macro was originally in milter.h, but no-one else needed it.
282      */
283 #define milter_macros_wipe(mp) do { \
284           MILTER_MACROS *__mp = mp; \
285           if (__mp->conn_macros) \
286               myfree(__mp->conn_macros); \
287           if (__mp->helo_macros) \
288               myfree(__mp->helo_macros); \
289           if (__mp->mail_macros) \
290               myfree(__mp->mail_macros); \
291           if (__mp->rcpt_macros) \
292               myfree(__mp->rcpt_macros); \
293           if (__mp->data_macros) \
294               myfree(__mp->data_macros); \
295           if (__mp->eoh_macros) \
296               myfree(__mp->eoh_macros); \
297           if (__mp->eod_macros) \
298               myfree(__mp->eod_macros); \
299           if (__mp->unk_macros) \
300               myfree(__mp->unk_macros); \
301     } while (0)
302 
303     milter_macros_wipe(mp);
304     myfree((void *) mp);
305 }
306