Postfix3.3.1
milter.c
[詳解]
1 /*++
2 /* NAME
3 /* milter 3
4 /* SUMMARY
5 /* generic MTA-side mail filter interface
6 /* SYNOPSIS
7 /* #include <milter.h>
8 /*
9 /* MILTERS *milter_create(milter_names, conn_timeout, cmd_timeout,
10 /* msg_timeout, protocol, def_action,
11 /* conn_macros, helo_macros,
12 /* mail_macros, rcpt_macros,
13 /* data_macros, eoh_macros,
14 /* eod_macros, unk_macros,
15 /* macro_deflts)
16 /* const char *milter_names;
17 /* int conn_timeout;
18 /* int cmd_timeout;
19 /* int msg_timeout;
20 /* const char *protocol;
21 /* const char *def_action;
22 /* const char *conn_macros;
23 /* const char *helo_macros;
24 /* const char *mail_macros;
25 /* const char *rcpt_macrps;
26 /* const char *data_macros;
27 /* const char *eoh_macros;
28 /* const char *eod_macros;
29 /* const char *unk_macros;
30 /* const char *macro_deflts;
31 /*
32 /* void milter_free(milters)
33 /* MILTERS *milters;
34 /*
35 /* void milter_macro_callback(milters, mac_lookup, mac_context)
36 /* const char *(*mac_lookup)(const char *name, void *context);
37 /* void *mac_context;
38 /*
39 /* void milter_edit_callback(milters, add_header, upd_header,
40 /* ins_header, del_header, chg_from,
41 /* add_rcpt, add_rcpt_par, del_rcpt,
42 /* repl_body, context)
43 /* MILTERS *milters;
44 /* MILTER_ADD_HEADER_FN add_header;
45 /* MILTER_EDIT_HEADER_FN upd_header;
46 /* MILTER_EDIT_HEADER_FN ins_header;
47 /* MILTER_DEL_HEADER_FN del_header;
48 /* MILTER_EDIT_FROM_FN chg_from;
49 /* MILTER_EDIT_RCPT_FN add_rcpt;
50 /* MILTER_EDIT_RCPT_PAR_FN add_rcpt_par;
51 /* MILTER_EDIT_RCPT_FN del_rcpt;
52 /* MILTER_EDIT_BODY_FN repl_body;
53 /* void *context;
54 /*
55 /* const char *milter_conn_event(milters, client_name, client_addr,
56 /* client_port, addr_family)
57 /* MILTERS *milters;
58 /* const char *client_name;
59 /* const char *client_addr;
60 /* const char *client_port;
61 /* int addr_family;
62 /*
63 /* const char *milter_disc_event(milters)
64 /* MILTERS *milters;
65 /*
66 /* const char *milter_helo_event(milters, helo_name, esmtp_flag)
67 /* MILTERS *milters;
68 /* const char *helo_name;
69 /* int esmtp_flag;
70 /*
71 /* const char *milter_mail_event(milters, argv)
72 /* MILTERS *milters;
73 /* const char **argv;
74 /*
75 /* const char *milter_rcpt_event(milters, flags, argv)
76 /* MILTERS *milters;
77 /* int flags;
78 /* const char **argv;
79 /*
80 /* const char *milter_data_event(milters)
81 /* MILTERS *milters;
82 /*
83 /* const char *milter_unknown_event(milters, command)
84 /* MILTERS *milters;
85 /* const char *command;
86 /*
87 /* const char *milter_other_event(milters)
88 /* MILTERS *milters;
89 /*
90 /* const char *milter_message(milters, qfile, data_offset, auto_hdrs)
91 /* MILTERS *milters;
92 /* VSTREAM *qfile;
93 /* off_t data_offset;
94 /* ARGV *auto_hdrs;
95 /*
96 /* const char *milter_abort(milters)
97 /* MILTERS *milters;
98 /*
99 /* int milter_send(milters, fp)
100 /* MILTERS *milters;
101 /* VSTREAM *fp;
102 /*
103 /* MILTERS *milter_receive(fp, count)
104 /* VSTREAM *fp;
105 /* int count;
106 /*
107 /* int milter_dummy(milters, fp)
108 /* MILTERS *milters;
109 /* VSTREAM *fp;
110 /* DESCRIPTION
111 /* The functions in this module manage one or more milter (mail
112 /* filter) clients. Currently, only the Sendmail 8 filter
113 /* protocol is supported.
114 /*
115 /* The functions that inspect content or envelope commands
116 /* return either an SMTP reply ([45]XX followed by enhanced
117 /* status code and text), "D" (discard), "H" (quarantine),
118 /* "S" (shutdown connection), or a null pointer, which means
119 /* "no news is good news".
120 /*
121 /* milter_create() instantiates the milter clients specified
122 /* with the milter_names argument. The conn_macros etc.
123 /* arguments specify the names of macros that are sent to the
124 /* mail filter applications upon a connect etc. event, and the
125 /* macro_deflts argument specifies macro defaults that will be used
126 /* only if the application's lookup call-back returns null. This
127 /* function should be called during process initialization,
128 /* before entering a chroot jail. The timeout parameters specify
129 /* time limits for the completion of the specified request
130 /* classes. The protocol parameter specifies a protocol version
131 /* and optional extensions. When the milter application is
132 /* unavailable, the milter client will go into a suitable error
133 /* state as specified with the def_action parameter (i.e.
134 /* reject, tempfail or accept all subsequent events).
135 /*
136 /* milter_free() disconnects from the milter instances that
137 /* are still opened, and destroys the data structures created
138 /* by milter_create(). This function is safe to call at any
139 /* point after milter_create().
140 /*
141 /* milter_macro_callback() specifies a call-back function and
142 /* context for macro lookup. This function must be called
143 /* before milter_conn_event().
144 /*
145 /* milter_edit_callback() specifies call-back functions and
146 /* context for editing the queue file after the end-of-data
147 /* is received. This function must be called before milter_message();
148 /*
149 /* milter_conn_event() reports an SMTP client connection event
150 /* to the specified milter instances, after sending the macros
151 /* specified with the milter_create() conn_macros argument.
152 /* This function must be called before reporting any other
153 /* events.
154 /*
155 /* milter_disc_event() reports an SMTP client disconnection
156 /* event to the specified milter instances. No events can
157 /* reported after this call. To simplify usage, redundant calls
158 /* of this function are NO-OPs and don't raise a run-time
159 /* error.
160 /*
161 /* milter_helo_event() reports a HELO or EHLO event to the
162 /* specified milter instances, after sending the macros that
163 /* were specified with the milter_create() helo_macros argument.
164 /*
165 /* milter_mail_event() reports a MAIL FROM event to the specified
166 /* milter instances, after sending the macros that were specified
167 /* with the milter_create() mail_macros argument.
168 /*
169 /* milter_rcpt_event() reports an RCPT TO event to the specified
170 /* milter instances, after sending the macros that were specified
171 /* with the milter_create() rcpt_macros argument. The flags
172 /* argument supports the following:
173 /* .IP MILTER_FLAG_WANT_RCPT_REJ
174 /* When this flag is cleared, invoke all milters. When this
175 /* flag is set, invoke only milters that want to receive
176 /* rejected recipients; with Sendmail V8 Milters, {rcpt_mailer}
177 /* is set to "error", {rcpt_host} is set to an enhanced status
178 /* code, and {rcpt_addr} is set to descriptive text.
179 /* .PP
180 /* milter_data_event() reports a DATA event to the specified
181 /* milter instances, after sending the macros that were specified
182 /* with the milter_create() data_macros argument.
183 /*
184 /* milter_unknown_event() reports an unknown command event to
185 /* the specified milter instances, after sending the macros
186 /* that were specified with the milter_create() unk_macros
187 /* argument.
188 /*
189 /* milter_other_event() returns the current default mail filter
190 /* reply for the current SMTP connection state; it does not
191 /* change milter states. A null pointer result means that all
192 /* is well. This function can be used for SMTP commands such
193 /* as AUTH, STARTTLS that don't have their own milter event
194 /* routine.
195 /*
196 /* milter_message() sends the message header and body to the
197 /* to the specified milter instances, and sends the macros
198 /* specified with the milter_create() eoh_macros after the
199 /* message header, and with the eod_macros argument at
200 /* the end. Each milter sees the result of any changes made
201 /* by a preceding milter. This function must be called with
202 /* as argument an open Postfix queue file.
203 /*
204 /* milter_abort() cancels a mail transaction in progress. To
205 /* simplify usage, redundant calls of this function are NO-OPs
206 /* and don't raise a run-time error.
207 /*
208 /* milter_send() sends a list of mail filters over the specified
209 /* stream. When given a null list pointer, a "no filter"
210 /* indication is sent. The result is non-zero in case of
211 /* error.
212 /*
213 /* milter_receive() receives the specified number of mail
214 /* filters over the specified stream. The result is a null
215 /* pointer when no milters were sent, or when an error happened.
216 /*
217 /* milter_dummy() is like milter_send(), except that it sends
218 /* a dummy, but entirely valid, mail filter list.
219 /* SEE ALSO
220 /* milter8(3) Sendmail 8 Milter protocol
221 /* DIAGNOSTICS
222 /* Panic: interface violation.
223 /* Fatal errors: memory allocation problem.
224 /* LICENSE
225 /* .ad
226 /* .fi
227 /* The Secure Mailer license must be distributed with this software.
228 /* AUTHOR(S)
229 /* Wietse Venema
230 /* IBM T.J. Watson Research
231 /* P.O. Box 704
232 /* Yorktown Heights, NY 10598, USA
233 /*
234 /* Wietse Venema
235 /* Google, Inc.
236 /* 111 8th Avenue
237 /* New York, NY 10011, USA
238 /*--*/
239 
240 /* System library. */
241 
242 #include <sys_defs.h>
243 
244 /* Utility library. */
245 
246 #include <msg.h>
247 #include <mymalloc.h>
248 #include <stringops.h>
249 #include <argv.h>
250 #include <attr.h>
251 #include <htable.h>
252 
253 /* Global library. */
254 
255 #include <mail_proto.h>
256 #include <record.h>
257 #include <rec_type.h>
258 #include <mail_params.h>
259 #include <attr_override.h>
260 
261 /* Postfix Milter library. */
262 
263 #include <milter.h>
264 
265 /* Application-specific. */
266 
267  /*
268  * SLMs.
269  */
270 #define STR(x) vstring_str(x)
271 
272 /* milter_macro_defaults_create - parse default macro entries */
273 
274 HTABLE *milter_macro_defaults_create(const char *macro_defaults)
275 {
276  const char myname[] = "milter_macro_defaults_create";
277  char *saved_defaults = mystrdup(macro_defaults);
278  char *cp = saved_defaults;
279  HTABLE *table = 0;
280  VSTRING *canon_buf = 0;
281  char *nameval;
282 
283  while ((nameval = mystrtokq(&cp, CHARS_COMMA_SP, CHARS_BRACE)) != 0) {
284  const char *err;
285  char *name;
286  char *value;
287 
288  /*
289  * Split the input into (name, value) pairs. Allow the forms
290  * name=value and { name = value }, where the last form ignores
291  * whitespace after the opening "{", around the "=", and before the
292  * closing "}". A name may also be specified as {name}.
293  *
294  * Use the form {name} for table lookups, because that is the form of
295  * the S8_MAC_* macro names.
296  */
297  if (*nameval == CHARS_BRACE[0]
298  && nameval[balpar(nameval, CHARS_BRACE)] != '='
299  && (err = extpar(&nameval, CHARS_BRACE, EXTPAR_FLAG_NONE)) != 0)
300  msg_fatal("malformed default macro entry: %s in \"%s\"",
301  err, macro_defaults);
302  if ((err = split_nameval(nameval, &name, &value)) != 0)
303  msg_fatal("malformed default macro entry: %s in \"%s\"",
304  err, macro_defaults);
305  if (*name != '{') /* } */
306  name = STR(vstring_sprintf(canon_buf ? canon_buf :
307  (canon_buf = vstring_alloc(20)), "{%s}", name));
308  if (table == 0)
309  table = htable_create(1);
310  if (htable_find(table, name) != 0) {
311  msg_warn("ignoring multiple default macro entries for %s in \"%s\"",
312  name, macro_defaults);
313  } else {
314  (void) htable_enter(table, name, mystrdup(value));
315  if (msg_verbose)
316  msg_info("%s: add name=%s default=%s", myname, name, value);
317  }
318  }
319  myfree(saved_defaults);
320  if (canon_buf)
321  vstring_free(canon_buf);
322  return (table);
323 }
324 
325 /* milter_macro_lookup - look up macros */
326 
327 static ARGV *milter_macro_lookup(MILTERS *milters, const char *macro_names)
328 {
329  const char *myname = "milter_macro_lookup";
330  char *saved_names = mystrdup(macro_names);
331  char *cp = saved_names;
332  ARGV *argv = argv_alloc(10);
333  VSTRING *canon_buf = vstring_alloc(20);
334  const char *value;
335  const char *name;
336  const char *cname;
337 
338  while ((name = mystrtok(&cp, CHARS_COMMA_SP)) != 0) {
339  if (msg_verbose)
340  msg_info("%s: \"%s\"", myname, name);
341  if (*name != '{') /* } */
342  cname = STR(vstring_sprintf(canon_buf, "{%s}", name));
343  else
344  cname = name;
345  if ((value = milters->mac_lookup(cname, milters->mac_context)) != 0) {
346  if (msg_verbose)
347  msg_info("%s: result \"%s\"", myname, value);
348  argv_add(argv, name, value, (char *) 0);
349  } else if (milters->macro_defaults != 0
350  && (value = htable_find(milters->macro_defaults, cname)) != 0) {
351  if (msg_verbose)
352  msg_info("%s: using default \"%s\"", myname, value);
353  argv_add(argv, name, value, (char *) 0);
354  }
355  }
356  myfree(saved_names);
357  vstring_free(canon_buf);
358  return (argv);
359 }
360 
361 /* milter_macro_callback - specify macro lookup */
362 
364  const char *(*mac_lookup) (const char *, void *),
365  void *mac_context)
366 {
367  milters->mac_lookup = mac_lookup;
368  milters->mac_context = mac_context;
369 }
370 
371 /* milter_edit_callback - specify queue file edit call-back information */
372 
374  MILTER_ADD_HEADER_FN add_header,
375  MILTER_EDIT_HEADER_FN upd_header,
376  MILTER_EDIT_HEADER_FN ins_header,
377  MILTER_DEL_HEADER_FN del_header,
378  MILTER_EDIT_FROM_FN chg_from,
380  MILTER_EDIT_RCPT_PAR_FN add_rcpt_par,
382  MILTER_EDIT_BODY_FN repl_body,
383  void *chg_context)
384 {
385  milters->add_header = add_header;
386  milters->upd_header = upd_header;
387  milters->ins_header = ins_header;
388  milters->del_header = del_header;
389  milters->chg_from = chg_from;
390  milters->add_rcpt = add_rcpt;
391  milters->add_rcpt_par = add_rcpt_par;
392  milters->del_rcpt = del_rcpt;
393  milters->repl_body = repl_body;
394  milters->chg_context = chg_context;
395 }
396 
397 /* milter_conn_event - report connect event */
398 
399 const char *milter_conn_event(MILTERS *milters,
400  const char *client_name,
401  const char *client_addr,
402  const char *client_port,
403  unsigned addr_family)
404 {
405  const char *resp;
406  MILTER *m;
407  ARGV *global_macros = 0;
408  ARGV *any_macros;
409 
410 #define MILTER_MACRO_EVAL(global_macros, m, milters, member) \
411  ((m->macros && m->macros->member[0]) ? \
412  milter_macro_lookup(milters, m->macros->member) : \
413  global_macros ? global_macros : \
414  (global_macros = \
415  milter_macro_lookup(milters, milters->macros->member)))
416 
417  if (msg_verbose)
418  msg_info("report connect to all milters");
419  for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next) {
420  any_macros = MILTER_MACRO_EVAL(global_macros, m, milters, conn_macros);
421  resp = m->conn_event(m, client_name, client_addr, client_port,
422  addr_family, any_macros);
423  if (any_macros != global_macros)
424  argv_free(any_macros);
425  }
426  if (global_macros)
427  argv_free(global_macros);
428  return (resp);
429 }
430 
431 /* milter_helo_event - report helo event */
432 
433 const char *milter_helo_event(MILTERS *milters, const char *helo_name,
434  int esmtp_flag)
435 {
436  const char *resp;
437  MILTER *m;
438  ARGV *global_macros = 0;
439  ARGV *any_macros;
440 
441  if (msg_verbose)
442  msg_info("report helo to all milters");
443  for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next) {
444  any_macros = MILTER_MACRO_EVAL(global_macros, m, milters, helo_macros);
445  resp = m->helo_event(m, helo_name, esmtp_flag, any_macros);
446  if (any_macros != global_macros)
447  argv_free(any_macros);
448  }
449  if (global_macros)
450  argv_free(global_macros);
451  return (resp);
452 }
453 
454 /* milter_mail_event - report mail from event */
455 
456 const char *milter_mail_event(MILTERS *milters, const char **argv)
457 {
458  const char *resp;
459  MILTER *m;
460  ARGV *global_macros = 0;
461  ARGV *any_macros;
462 
463  if (msg_verbose)
464  msg_info("report sender to all milters");
465  for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next) {
466  any_macros = MILTER_MACRO_EVAL(global_macros, m, milters, mail_macros);
467  resp = m->mail_event(m, argv, any_macros);
468  if (any_macros != global_macros)
469  argv_free(any_macros);
470  }
471  if (global_macros)
472  argv_free(global_macros);
473  return (resp);
474 }
475 
476 /* milter_rcpt_event - report rcpt to event */
477 
478 const char *milter_rcpt_event(MILTERS *milters, int flags, const char **argv)
479 {
480  const char *resp;
481  MILTER *m;
482  ARGV *global_macros = 0;
483  ARGV *any_macros;
484 
485  if (msg_verbose)
486  msg_info("report recipient to all milters (flags=0x%x)", flags);
487  for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next) {
488  if ((flags & MILTER_FLAG_WANT_RCPT_REJ) == 0
489  || (m->flags & MILTER_FLAG_WANT_RCPT_REJ) != 0) {
490  any_macros =
491  MILTER_MACRO_EVAL(global_macros, m, milters, rcpt_macros);
492  resp = m->rcpt_event(m, argv, any_macros);
493  if (any_macros != global_macros)
494  argv_free(any_macros);
495  }
496  }
497  if (global_macros)
498  argv_free(global_macros);
499  return (resp);
500 }
501 
502 /* milter_data_event - report data event */
503 
504 const char *milter_data_event(MILTERS *milters)
505 {
506  const char *resp;
507  MILTER *m;
508  ARGV *global_macros = 0;
509  ARGV *any_macros;
510 
511  if (msg_verbose)
512  msg_info("report data to all milters");
513  for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next) {
514  any_macros = MILTER_MACRO_EVAL(global_macros, m, milters, data_macros);
515  resp = m->data_event(m, any_macros);
516  if (any_macros != global_macros)
517  argv_free(any_macros);
518  }
519  if (global_macros)
520  argv_free(global_macros);
521  return (resp);
522 }
523 
524 /* milter_unknown_event - report unknown command */
525 
526 const char *milter_unknown_event(MILTERS *milters, const char *command)
527 {
528  const char *resp;
529  MILTER *m;
530  ARGV *global_macros = 0;
531  ARGV *any_macros;
532 
533  if (msg_verbose)
534  msg_info("report unknown command to all milters");
535  for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next) {
536  any_macros = MILTER_MACRO_EVAL(global_macros, m, milters, unk_macros);
537  resp = m->unknown_event(m, command, any_macros);
538  if (any_macros != global_macros)
539  argv_free(any_macros);
540  }
541  if (global_macros)
542  argv_free(global_macros);
543  return (resp);
544 }
545 
546 /* milter_other_event - other SMTP event */
547 
548 const char *milter_other_event(MILTERS *milters)
549 {
550  const char *resp;
551  MILTER *m;
552 
553  if (msg_verbose)
554  msg_info("query milter states for other event");
555  for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next)
556  resp = m->other_event(m);
557  return (resp);
558 }
559 
560 /* milter_message - inspect message content */
561 
562 const char *milter_message(MILTERS *milters, VSTREAM *fp, off_t data_offset,
563  ARGV *auto_hdrs)
564 {
565  const char *resp;
566  MILTER *m;
567  ARGV *global_eoh_macros = 0;
568  ARGV *global_eod_macros = 0;
569  ARGV *any_eoh_macros;
570  ARGV *any_eod_macros;
571 
572  if (msg_verbose)
573  msg_info("inspect content by all milters");
574  for (resp = 0, m = milters->milter_list; resp == 0 && m != 0; m = m->next) {
575  any_eoh_macros = MILTER_MACRO_EVAL(global_eoh_macros, m, milters, eoh_macros);
576  any_eod_macros = MILTER_MACRO_EVAL(global_eod_macros, m, milters, eod_macros);
577  resp = m->message(m, fp, data_offset, any_eoh_macros, any_eod_macros,
578  auto_hdrs);
579  if (any_eoh_macros != global_eoh_macros)
580  argv_free(any_eoh_macros);
581  if (any_eod_macros != global_eod_macros)
582  argv_free(any_eod_macros);
583  }
584  if (global_eoh_macros)
585  argv_free(global_eoh_macros);
586  if (global_eod_macros)
587  argv_free(global_eod_macros);
588  return (resp);
589 }
590 
591 /* milter_abort - cancel message receiving state, all milters */
592 
593 void milter_abort(MILTERS *milters)
594 {
595  MILTER *m;
596 
597  if (msg_verbose)
598  msg_info("abort all milters");
599  for (m = milters->milter_list; m != 0; m = m->next)
600  m->abort(m);
601 }
602 
603 /* milter_disc_event - report client disconnect event to all milters */
604 
606 {
607  MILTER *m;
608 
609  if (msg_verbose)
610  msg_info("disconnect event to all milters");
611  for (m = milters->milter_list; m != 0; m = m->next)
612  m->disc_event(m);
613 }
614 
615  /*
616  * Table-driven parsing of main.cf parameter overrides for specific Milters.
617  * We derive the override names from the corresponding main.cf parameter
618  * names by skipping the redundant "milter_" prefix.
619  */
620 static ATTR_OVER_TIME time_table[] = {
622  7 + VAR_MILT_CMD_TIME, DEF_MILT_CMD_TIME, 0, 1, 0,
623  7 + VAR_MILT_MSG_TIME, DEF_MILT_MSG_TIME, 0, 1, 0,
624  0,
625 };
626 static ATTR_OVER_STR str_table[] = {
627  7 + VAR_MILT_PROTOCOL, 0, 1, 0,
628  7 + VAR_MILT_DEF_ACTION, 0, 1, 0,
629  0,
630 };
631 
632 #define link_override_table_to_variable(table, var) \
633  do { table[var##_offset].target = &var; } while (0)
634 
635 #define my_conn_timeout_offset 0
636 #define my_cmd_timeout_offset 1
637 #define my_msg_timeout_offset 2
638 
639 #define my_protocol_offset 0
640 #define my_def_action_offset 1
641 
642 /* milter_new - create milter list */
643 
644 MILTERS *milter_new(const char *names,
645  int conn_timeout,
646  int cmd_timeout,
647  int msg_timeout,
648  const char *protocol,
649  const char *def_action,
650  MILTER_MACROS *macros,
651  HTABLE *macro_defaults)
652 {
653  MILTERS *milters;
654  MILTER *head = 0;
655  MILTER *tail = 0;
656  char *name;
657  MILTER *milter;
658  const char *sep = CHARS_COMMA_SP;
659  const char *parens = CHARS_BRACE;
660  int my_conn_timeout;
661  int my_cmd_timeout;
662  int my_msg_timeout;
663  const char *my_protocol;
664  const char *my_def_action;
665 
666  /*
667  * Initialize.
668  */
669  link_override_table_to_variable(time_table, my_conn_timeout);
670  link_override_table_to_variable(time_table, my_cmd_timeout);
671  link_override_table_to_variable(time_table, my_msg_timeout);
672  link_override_table_to_variable(str_table, my_protocol);
673  link_override_table_to_variable(str_table, my_def_action);
674 
675  /*
676  * Parse the milter list.
677  */
678  milters = (MILTERS *) mymalloc(sizeof(*milters));
679  if (names != 0 && *names != 0) {
680  char *saved_names = mystrdup(names);
681  char *cp = saved_names;
682  char *op;
683  char *err;
684 
685  /*
686  * Instantiate Milters, allowing for per-Milter overrides.
687  */
688  while ((name = mystrtokq(&cp, sep, parens)) != 0) {
689  my_conn_timeout = conn_timeout;
690  my_cmd_timeout = cmd_timeout;
691  my_msg_timeout = msg_timeout;
692  my_protocol = protocol;
693  my_def_action = def_action;
694  if (name[0] == parens[0]) {
695  op = name;
696  if ((err = extpar(&op, parens, EXTPAR_FLAG_NONE)) != 0)
697  msg_fatal("milter service syntax error: %s", err);
698  if ((name = mystrtok(&op, sep)) == 0)
699  msg_fatal("empty milter definition: \"%s\"", names);
700  attr_override(op, sep, parens,
701  CA_ATTR_OVER_STR_TABLE(str_table),
702  CA_ATTR_OVER_TIME_TABLE(time_table),
704  }
705  milter = milter8_create(name, my_conn_timeout, my_cmd_timeout,
706  my_msg_timeout, my_protocol,
707  my_def_action, milters);
708  if (head == 0) {
709  head = milter;
710  } else {
711  tail->next = milter;
712  }
713  tail = milter;
714  }
715  myfree(saved_names);
716  }
717  milters->milter_list = head;
718  milters->mac_lookup = 0;
719  milters->mac_context = 0;
720  milters->macros = macros;
721  milters->macro_defaults = macro_defaults;
722  milters->add_header = 0;
723  milters->upd_header = milters->ins_header = 0;
724  milters->del_header = 0;
725  milters->add_rcpt = milters->del_rcpt = 0;
726  milters->repl_body = 0;
727  milters->chg_context = 0;
728  return (milters);
729 }
730 
731 /* milter_free - destroy all milters */
732 
733 void milter_free(MILTERS *milters)
734 {
735  MILTER *m;
736  MILTER *next;
737 
738  if (msg_verbose)
739  msg_info("free all milters");
740  for (m = milters->milter_list; m != 0; m = next)
741  next = m->next, m->free(m);
742  if (milters->macros)
743  milter_macros_free(milters->macros);
744  if (milters->macro_defaults)
745  htable_free(milters->macro_defaults, myfree);
746  myfree((void *) milters);
747 }
748 
749 /* milter_dummy - send empty milter list */
750 
751 int milter_dummy(MILTERS *milters, VSTREAM *stream)
752 {
753  MILTERS dummy = *milters;
754 
755  dummy.milter_list = 0;
756  return (milter_send(&dummy, stream));
757 }
758 
759 /* milter_send - send Milter instances over stream */
760 
761 int milter_send(MILTERS *milters, VSTREAM *stream)
762 {
763  MILTER *m;
764  int status = 0;
765  int count = 0;
766 
767  /*
768  * XXX Optimization: send only the filters that are actually used in the
769  * remote process. No point sending a filter that looks at HELO commands
770  * to a cleanup server. For now we skip only the filters that are known
771  * to be disabled (either in global error state or in global accept
772  * state).
773  *
774  * XXX We must send *some* information, even when there are no active
775  * filters, otherwise the cleanup server would try to apply its own
776  * non_smtpd_milters settings.
777  */
778  if (milters != 0)
779  for (m = milters->milter_list; m != 0; m = m->next)
780  if (m->active(m))
781  count++;
782  (void) rec_fprintf(stream, REC_TYPE_MILT_COUNT, "%d", count);
783 
784  if (msg_verbose)
785  msg_info("send %d milters", count);
786 
787  /*
788  * XXX Optimization: don't send or receive further information when there
789  * aren't any active filters.
790  */
791  if (count <= 0)
792  return (0);
793 
794  /*
795  * Send the filter macro name lists.
796  */
797  (void) attr_print(stream, ATTR_FLAG_MORE,
799  (void *) milters->macros),
800  ATTR_TYPE_END);
801 
802  /*
803  * Send the filter macro defaults.
804  */
805  count = milters->macro_defaults ? milters->macro_defaults->used : 0;
806  (void) attr_print(stream, ATTR_FLAG_MORE,
808  ATTR_TYPE_END);
809  if (count > 0)
810  (void) attr_print(stream, ATTR_FLAG_MORE,
811  SEND_ATTR_HASH(milters->macro_defaults),
812  ATTR_TYPE_END);
813 
814  /*
815  * Send the filter instances.
816  */
817  for (m = milters->milter_list; m != 0; m = m->next)
818  if (m->active(m) && (status = m->send(m, stream)) != 0)
819  break;
820 
821  /*
822  * Over to you.
823  */
824  if (status != 0
825  || attr_scan(stream, ATTR_FLAG_STRICT,
827  ATTR_TYPE_END) != 1
828  || status != 0) {
829  msg_warn("cannot send milters to service %s", VSTREAM_PATH(stream));
830  return (-1);
831  }
832  return (0);
833 }
834 
835 /* milter_receive - receive milters from stream */
836 
837 MILTERS *milter_receive(VSTREAM *stream, int count)
838 {
839  MILTERS *milters;
840  MILTER *head = 0;
841  MILTER *tail = 0;
842  MILTER *milter = 0;
843  int macro_default_count;
844 
845  if (msg_verbose)
846  msg_info("receive %d milters", count);
847 
848  /*
849  * XXX We must instantiate a MILTERS structure even when the sender has
850  * no active filters, otherwise the cleanup server would try to use its
851  * own non_smtpd_milters settings.
852  */
853 #define NO_MILTERS ((char *) 0)
854 #define NO_TIMEOUTS 0, 0, 0
855 #define NO_PROTOCOL ((char *) 0)
856 #define NO_ACTION ((char *) 0)
857 #define NO_MACROS ((MILTER_MACROS *) 0)
858 #define NO_MACRO_DEFLTS ((HTABLE *) 0)
859 
862 
863  /*
864  * XXX Optimization: don't send or receive further information when there
865  * aren't any active filters.
866  */
867  if (count <= 0)
868  return (milters);
869 
870  /*
871  * Receive the global macro name lists.
872  */
876  (void *) milters->macros),
877  ATTR_TYPE_END) != 1) {
878  milter_free(milters);
879  return (0);
880  }
881 
882  /*
883  * Receive the filter macro defaults.
884  */
886  RECV_ATTR_INT(MAIL_ATTR_SIZE, &macro_default_count),
887  ATTR_TYPE_END) != 1
888  || (macro_default_count > 0
891  = htable_create(1)),
892  ATTR_TYPE_END) != macro_default_count)) {
893  milter_free(milters);
894  return (0);
895  }
896 
897  /*
898  * Receive the filters.
899  */
900  for (; count > 0; count--) {
901  if ((milter = milter8_receive(stream, milters)) == 0) {
902  msg_warn("cannot receive milters via service %s socket",
903  VSTREAM_PATH(stream));
904  milter_free(milters);
905  return (0);
906  }
907  if (head == 0) {
908  /* Coverity: milter_free() depends on milters->milter_list. */
909  milters->milter_list = head = milter;
910  } else {
911  tail->next = milter;
912  }
913  tail = milter;
914  }
915 
916  /*
917  * Over to you.
918  */
919  (void) attr_print(stream, ATTR_FLAG_NONE,
921  ATTR_TYPE_END);
922  return (milters);
923 }
924 
925 #ifdef TEST
926 
927  /*
928  * Proof-of-concept test program. This can be used interactively, but is
929  * typically used for automated regression tests from a script.
930  */
931 
932 /* System library. */
933 
934 #include <sys/socket.h>
935 #include <stdlib.h>
936 #include <string.h>
937 
938 /* Utility library. */
939 
940 #include "msg_vstream.h"
941 #include "vstring_vstream.h"
942 
943 /* Global library. */
944 
945 #include <mail_params.h>
946 
947 int var_milt_conn_time = 10;
948 int var_milt_cmd_time = 10;
949 int var_milt_msg_time = 100;
952 
953 static void usage(void)
954 {
955  vstream_fprintf(VSTREAM_ERR, "usage: \n"
956  " create names... create and connect\n"
957 #if 0
958  " conn_macros names... define connect macros\n"
959  " helo_macros names... define helo command macros\n"
960  " mail_macros names... define mail command macros\n"
961  " rcpt_macros names... define rcpt command macros\n"
962  " data_macros names... define data command macros\n"
963  " unk_macros names... unknown command macros\n"
964  " message_macros names... define message macros\n"
965 #endif
966  " free disconnect and destroy\n"
967  " connect name addr port family\n"
968  " helo hostname\n"
969  " ehlo hostname\n"
970  " mail from sender...\n"
971  " rcpt to recipient...\n"
972  " data\n"
973  " disconnect\n"
974  " unknown command\n");
976 }
977 
978 int main(int argc, char **argv)
979 {
980  MILTERS *milters = 0;
981  char *conn_macros, *helo_macros, *mail_macros, *rcpt_macros;
982  char *data_macros, *eoh_macros, *eod_macros, *unk_macros;
983  char *macro_deflts;
984  VSTRING *inbuf = vstring_alloc(100);
985  char *bufp;
986  char *cmd;
987  int ch;
988  int istty = isatty(vstream_fileno(VSTREAM_IN));
989 
990  conn_macros = helo_macros = mail_macros = rcpt_macros = data_macros
991  = eoh_macros = eod_macros = unk_macros = macro_deflts = "";
992 
993  msg_vstream_init(argv[0], VSTREAM_ERR);
994  while ((ch = GETOPT(argc, argv, "V:v")) > 0) {
995  switch (ch) {
996  default:
997  msg_fatal("usage: %s [-a action] [-p protocol] [-v]", argv[0]);
998  case 'a':
999  var_milt_def_action = optarg;
1000  break;
1001  case 'p':
1002  var_milt_protocol = optarg;
1003  break;
1004  case 'v':
1005  msg_verbose++;
1006  break;
1007  }
1008  }
1009  optind = OPTIND;
1010 
1011  for (;;) {
1012  const char *resp = 0;
1013  ARGV *argv;
1014  char **args;
1015 
1016  if (istty) {
1017  vstream_printf("- ");
1019  }
1020  if (vstring_fgets_nonl(inbuf, VSTREAM_IN) <= 0)
1021  break;
1022  bufp = vstring_str(inbuf);
1023  if (!istty) {
1024  vstream_printf("> %s\n", bufp);
1026  }
1027  if (*bufp == '#')
1028  continue;
1029  cmd = mystrtok(&bufp, " ");
1030  if (cmd == 0) {
1031  usage();
1032  continue;
1033  }
1034  argv = argv_split(bufp, " ");
1035  args = argv->argv;
1036  if (strcmp(cmd, "create") == 0 && argv->argc == 1) {
1037  if (milters != 0) {
1038  msg_warn("deleting existing milters");
1039  milter_free(milters);
1040  }
1041  milters = milter_create(args[0], var_milt_conn_time,
1042  var_milt_cmd_time, var_milt_msg_time,
1043  var_milt_protocol, var_milt_def_action,
1044  conn_macros, helo_macros, mail_macros,
1045  rcpt_macros, data_macros, eoh_macros,
1046  eod_macros, unk_macros, macro_deflts);
1047  } else if (strcmp(cmd, "free") == 0 && argv->argc == 0) {
1048  if (milters == 0) {
1049  msg_warn("no milters");
1050  continue;
1051  }
1052  milter_free(milters);
1053  milters = 0;
1054  } else if (strcmp(cmd, "connect") == 0 && argv->argc == 4) {
1055  if (milters == 0) {
1056  msg_warn("no milters");
1057  continue;
1058  }
1059  resp = milter_conn_event(milters, args[0], args[1], args[2],
1060  strcmp(args[3], "AF_INET") == 0 ? AF_INET :
1061  strcmp(args[3], "AF_INET6") == 0 ? AF_INET6 :
1062  strcmp(args[3], "AF_UNIX") == 0 ? AF_UNIX :
1063  AF_UNSPEC);
1064  } else if (strcmp(cmd, "helo") == 0 && argv->argc == 1) {
1065  if (milters == 0) {
1066  msg_warn("no milters");
1067  continue;
1068  }
1069  resp = milter_helo_event(milters, args[0], 0);
1070  } else if (strcmp(cmd, "ehlo") == 0 && argv->argc == 1) {
1071  if (milters == 0) {
1072  msg_warn("no milters");
1073  continue;
1074  }
1075  resp = milter_helo_event(milters, args[0], 1);
1076  } else if (strcmp(cmd, "mail") == 0 && argv->argc > 0) {
1077  if (milters == 0) {
1078  msg_warn("no milters");
1079  continue;
1080  }
1081  resp = milter_mail_event(milters, (const char **) args);
1082  } else if (strcmp(cmd, "rcpt") == 0 && argv->argc > 0) {
1083  if (milters == 0) {
1084  msg_warn("no milters");
1085  continue;
1086  }
1087  resp = milter_rcpt_event(milters, 0, (const char **) args);
1088  } else if (strcmp(cmd, "unknown") == 0 && argv->argc > 0) {
1089  if (milters == 0) {
1090  msg_warn("no milters");
1091  continue;
1092  }
1093  resp = milter_unknown_event(milters, args[0]);
1094  } else if (strcmp(cmd, "data") == 0 && argv->argc == 0) {
1095  if (milters == 0) {
1096  msg_warn("no milters");
1097  continue;
1098  }
1099  resp = milter_data_event(milters);
1100  } else if (strcmp(cmd, "disconnect") == 0 && argv->argc == 0) {
1101  if (milters == 0) {
1102  msg_warn("no milters");
1103  continue;
1104  }
1105  milter_disc_event(milters);
1106  } else {
1107  usage();
1108  }
1109  if (resp != 0)
1110  msg_info("%s", resp);
1111  argv_free(argv);
1112  }
1113  if (milters != 0)
1114  milter_free(milters);
1115  vstring_free(inbuf);
1116  return (0);
1117 }
1118 
1119 #endif
int msg_verbose
Definition: msg.c:177
MILTER_EDIT_BODY_FN repl_body
Definition: milter.h:119
void htable_free(HTABLE *table, void(*free_fn)(void *))
Definition: htable.c:287
#define vstring_fgets_nonl(s, p)
#define ATTR_FLAG_NONE
Definition: attr.h:98
MILTER_EDIT_RCPT_FN del_rcpt
Definition: milter.h:118
void myfree(void *ptr)
Definition: mymalloc.c:207
#define CA_ATTR_OVER_END
Definition: attr_override.h:50
#define CHARS_BRACE
Definition: sys_defs.h:1763
const char *(* conn_event)(struct MILTER *, const char *, const char *, const char *, unsigned, ARGV *)
Definition: milter.h:38
char * mystrdup(const char *str)
Definition: mymalloc.c:225
char * extpar(char **bp, const char *parens, int flags)
Definition: extpar.c:77
char * var_milt_protocol
Definition: cleanup_init.c:156
const char *(* MILTER_EDIT_BODY_FN)(void *, int, VSTRING *)
Definition: milter.h:102
#define SEND_ATTR_HASH(val)
Definition: attr.h:65
ARGV * argv_free(ARGV *argvp)
Definition: argv.c:136
Definition: argv.h:17
MILTER_EDIT_HEADER_FN ins_header
Definition: milter.h:114
const char *(* helo_event)(struct MILTER *, const char *, int, ARGV *)
Definition: milter.h:39
MILTERS * milter_new(const char *names, int conn_timeout, int cmd_timeout, int msg_timeout, const char *protocol, const char *def_action, MILTER_MACROS *macros, HTABLE *macro_defaults)
Definition: milter.c:644
const char *(* MILTER_EDIT_RCPT_FN)(void *, const char *)
Definition: milter.h:100
#define vstring_str(vp)
Definition: vstring.h:71
const char * milter_other_event(MILTERS *milters)
Definition: milter.c:548
#define VSTREAM_OUT
Definition: vstream.h:67
#define EXTPAR_FLAG_NONE
Definition: stringops.h:56
MILTER_EDIT_RCPT_PAR_FN add_rcpt_par
Definition: milter.h:117
#define DEF_MILT_DEF_ACTION
Definition: mail_params.h:3413
#define VAR_MILT_PROTOCOL
Definition: mail_params.h:3408
ssize_t used
Definition: htable.h:27
int main(int argc, char **argv)
Definition: anvil.c:1010
void * chg_context
Definition: milter.h:110
#define MAIL_ATTR_SIZE
Definition: mail_proto.h:139
void attr_override(char *cp, const char *sep, const char *parens,...)
Definition: attr_override.c:91
int milter_macros_print(ATTR_PRINT_MASTER_FN, VSTREAM *, int, void *)
void milter_macros_free(MILTER_MACROS *)
#define DEF_MILT_MSG_TIME
Definition: mail_params.h:3405
char ** argv
Definition: argv.h:20
#define DEF_MILT_CONN_TIME
Definition: mail_params.h:3397
#define DEF_MILT_CMD_TIME
Definition: mail_params.h:3401
const char *(* MILTER_EDIT_FROM_FN)(void *, const char *, const char *)
Definition: milter.h:99
#define RECV_ATTR_INT(name, val)
Definition: attr.h:71
#define ATTR_TYPE_END
Definition: attr.h:39
#define VSTREAM_PATH(vp)
Definition: vstream.h:126
void argv_add(ARGV *argvp,...)
Definition: argv.c:197
MILTER_EDIT_FROM_FN chg_from
Definition: milter.h:115
char * mystrtokq(char **src, const char *sep, const char *parens)
Definition: mystrtok.c:80
#define RECV_ATTR_HASH(val)
Definition: attr.h:73
#define VSTREAM_IN
Definition: vstream.h:66
void * mac_context
Definition: milter.h:107
#define DEF_MILT_PROTOCOL
Definition: mail_params.h:3409
void(* free)(struct MILTER *)
Definition: milter.h:50
const char * milter_message(MILTERS *milters, VSTREAM *fp, off_t data_offset, ARGV *auto_hdrs)
Definition: milter.c:562
char * mystrtok(char **src, const char *sep)
Definition: mystrtok.c:54
ARGV * argv_alloc(ssize_t len)
Definition: argv.c:149
Definition: htable.h:25
#define CA_ATTR_OVER_TIME_TABLE(v)
Definition: attr_override.h:52
const char * split_nameval(char *buf, char **name, char **value)
Definition: split_nameval.c:61
#define REC_TYPE_MILT_COUNT
Definition: rec_type.h:75
const char *(* MILTER_ADD_HEADER_FN)(void *, const char *, const char *, const char *)
Definition: milter.h:96
char * del_rcpt[MAX_RCPT]
Definition: test-milter.c:173
const char * milter_helo_event(MILTERS *milters, const char *helo_name, int esmtp_flag)
Definition: milter.c:433
MILTERS * milter_receive(VSTREAM *stream, int count)
Definition: milter.c:837
MILTER * milter_list
Definition: milter.h:105
MILTER_ADD_HEADER_FN add_header
Definition: milter.h:111
HTABLE * htable_create(ssize_t size)
Definition: htable.c:179
MILTER_EDIT_RCPT_FN add_rcpt
Definition: milter.h:116
HTABLE * milter_macro_defaults_create(const char *macro_defaults)
Definition: milter.c:274
#define MILTER_FLAG_WANT_RCPT_REJ
Definition: milter.h:54
const char * milter_unknown_event(MILTERS *milters, const char *command)
Definition: milter.c:526
const char *(* MILTER_EDIT_HEADER_FN)(void *, ssize_t, const char *, const char *, const char *)
Definition: milter.h:97
int milter_dummy(MILTERS *milters, VSTREAM *stream)
Definition: milter.c:751
const char *(* other_event)(struct MILTER *)
Definition: milter.h:45
char * add_rcpt[MAX_RCPT]
Definition: test-milter.c:171
#define attr_print
Definition: attr.h:109
#define NO_ACTION
const char * milter_mail_event(MILTERS *milters, const char **argv)
Definition: milter.c:456
#define VAR_MILT_CMD_TIME
Definition: mail_params.h:3400
VSTREAM * vstream_fprintf(VSTREAM *stream, const char *fmt,...)
Definition: vstream.c:1348
int(* active)(struct MILTER *)
Definition: milter.h:48
#define NO_MILTERS
int milter_macros_scan(ATTR_SCAN_MASTER_FN, VSTREAM *, int, void *)
struct MILTER * next
Definition: milter.h:35
void milter_abort(MILTERS *milters)
Definition: milter.c:593
const char *(* mail_event)(struct MILTER *, const char **, ARGV *)
Definition: milter.h:40
VSTREAM * vstream_printf(const char *fmt,...)
Definition: vstream.c:1335
#define VAR_MILT_MSG_TIME
Definition: mail_params.h:3404
#define VAR_MILT_CONN_TIME
Definition: mail_params.h:3396
#define CA_ATTR_OVER_STR_TABLE(v)
Definition: attr_override.h:51
void msg_warn(const char *fmt,...)
Definition: msg.c:215
const char *(* message)(struct MILTER *, VSTREAM *, off_t, ARGV *, ARGV *, ARGV *)
Definition: milter.h:43
MILTER * milter8_receive(VSTREAM *, struct MILTERS *)
Definition: milter8.c:2714
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
void milter_disc_event(MILTERS *milters)
Definition: milter.c:605
const char * milter_rcpt_event(MILTERS *milters, int flags, const char **argv)
Definition: milter.c:478
#define STR(x)
Definition: milter.c:270
void * htable_find(HTABLE *table, const char *key)
Definition: htable.c:227
const char *(* MILTER_DEL_HEADER_FN)(void *, ssize_t, const char *)
Definition: milter.h:98
VSTRING * vstring_sprintf(VSTRING *vp, const char *format,...)
Definition: vstring.c:602
#define MAIL_ATTR_STATUS
Definition: mail_proto.h:126
#define SEND_ATTR_INT(name, val)
Definition: attr.h:63
void milter_free(MILTERS *milters)
Definition: milter.c:733
#define NO_PROTOCOL
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
#define NO_MACROS
#define CHARS_COMMA_SP
Definition: sys_defs.h:1761
int var_milt_msg_time
Definition: cleanup_init.c:155
#define NO_TIMEOUTS
const char * milter_data_event(MILTERS *milters)
Definition: milter.c:504
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
#define link_override_table_to_variable(table, var)
Definition: milter.c:632
ARGV * argv_split(const char *, const char *)
Definition: argv_split.c:63
struct MILTER_MACROS * macros
Definition: milter.h:108
#define GETOPT(argc, argv, str)
Definition: sys_defs.h:1313
void milter_edit_callback(MILTERS *milters, MILTER_ADD_HEADER_FN add_header, MILTER_EDIT_HEADER_FN upd_header, MILTER_EDIT_HEADER_FN ins_header, MILTER_DEL_HEADER_FN del_header, MILTER_EDIT_FROM_FN chg_from, MILTER_EDIT_RCPT_FN add_rcpt, MILTER_EDIT_RCPT_PAR_FN add_rcpt_par, MILTER_EDIT_RCPT_FN del_rcpt, MILTER_EDIT_BODY_FN repl_body, void *chg_context)
Definition: milter.c:373
int var_milt_conn_time
Definition: cleanup_init.c:153
int flags
Definition: milter.h:34
#define SEND_ATTR_FUNC(func, val)
Definition: attr.h:69
#define OPTIND
int(* send)(struct MILTER *, VSTREAM *)
Definition: milter.h:49
char * var_milt_def_action
Definition: cleanup_init.c:157
size_t balpar(const char *string, const char *parens)
Definition: balpar.c:39
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
#define vstream_fileno(vp)
Definition: vstream.h:115
const char * milter_conn_event(MILTERS *milters, const char *client_name, const char *client_addr, const char *client_port, unsigned addr_family)
Definition: milter.c:399
void msg_vstream_init(const char *name, VSTREAM *vp)
Definition: msg_vstream.c:77
#define VAR_MILT_DEF_ACTION
Definition: mail_params.h:3412
#define RECV_ATTR_FUNC(func, val)
Definition: attr.h:77
const char *(* MILTER_EDIT_RCPT_PAR_FN)(void *, const char *, const char *)
Definition: milter.h:101
ssize_t argc
Definition: argv.h:19
MILTER_DEL_HEADER_FN del_header
Definition: milter.h:113
MILTER_EDIT_HEADER_FN upd_header
Definition: milter.h:112
#define NO_MACRO_DEFLTS
MILTER_MACROS * milter_macros_alloc(int)
const char *(* data_event)(struct MILTER *, ARGV *)
Definition: milter.h:42
#define attr_scan
Definition: attr.h:111
void milter_macro_callback(MILTERS *milters, const char *(*mac_lookup)(const char *, void *), void *mac_context)
Definition: milter.c:363
const char *(* unknown_event)(struct MILTER *, const char *, ARGV *)
Definition: milter.h:44
void(* disc_event)(struct MILTER *)
Definition: milter.h:47
int rec_fprintf(VSTREAM *stream, int type, const char *format,...)
Definition: record.c:391
#define ATTR_FLAG_MORE
Definition: attr.h:101
Definition: milter.h:32
void(* abort)(struct MILTER *)
Definition: milter.h:46
const char *(* rcpt_event)(struct MILTER *, const char **, ARGV *)
Definition: milter.h:41
int var_milt_cmd_time
Definition: cleanup_init.c:154
#define MILTER_MACROS_ALLOC_ZERO
Definition: milter.h:84
#define VSTREAM_ERR
Definition: vstream.h:68
#define MILTER_MACRO_EVAL(global_macros, m, milters, member)
int milter_send(MILTERS *milters, VSTREAM *stream)
Definition: milter.c:761
void * mymalloc(ssize_t len)
Definition: mymalloc.c:150
MILTER_MAC_LOOKUP_FN mac_lookup
Definition: milter.h:106
#define ATTR_FLAG_STRICT
Definition: attr.h:103
MILTER * milter8_create(const char *, int, int, int, const char *, const char *, struct MILTERS *)
Definition: milter8.c:2876
struct HTABLE * macro_defaults
Definition: milter.h:109
HTABLE_INFO * htable_enter(HTABLE *table, const char *key, void *value)
Definition: htable.c:212
void msg_info(const char *fmt,...)
Definition: msg.c:199
#define milter_create(milter_names, conn_timeout, cmd_timeout, msg_timeout, protocol, def_action, conn_macros, helo_macros, mail_macros, rcpt_macros, data_macros, eoh_macros, eod_macros, unk_macros, macro_deflts)
Definition: milter.h:122