Postfix3.3.1
test-milter.c
[詳解]
1 /*++
2 /* NAME
3 /* test-milter 1
4 /* SUMMARY
5 /* Simple test mail filter program.
6 /* SYNOPSIS
7 /* .fi
8 /* \fBtest-milter\fR [\fIoptions\fR] -p \fBinet:\fIport\fB@\fIhost\fR
9 /*
10 /* \fBtest-milter\fR [\fIoptions\fR] -p \fBunix:\fIpathname\fR
11 /* DESCRIPTION
12 /* \fBtest-milter\fR is a Milter (mail filter) application that
13 /* exercises selected features.
14 /*
15 /* Note: this is an unsupported test program. No attempt is made
16 /* to maintain compatibility between successive versions.
17 /*
18 /* Arguments (multiple alternatives are separated by "\fB|\fR"):
19 /* .IP "\fB-a accept|tempfail|reject|discard|skip|\fIddd x.y.z text\fR"
20 /* Specifies a non-default reply for the MTA command specified
21 /* with \fB-c\fR. The default is \fBtempfail\fR.
22 /* .IP "\fB-A address\fR"
23 /* Add the specified recipient address (specify ESMTP parameters
24 /* separated by space). Multiple -A options are supported.
25 /* .IP "\fB-b pathname\fR"
26 /* Replace the message body by the content of the specified file.
27 /* .IP "\fB-c connect|helo|mail|rcpt|data|header|eoh|body|eom|unknown|close|abort\fR"
28 /* When to send the non-default reply specified with \fB-a\fR.
29 /* The default protocol stage is \fBconnect\fR.
30 /* .IP "\fB-C\fI count\fR"
31 /* Terminate after \fIcount\fR connections.
32 /* .IP "\fB-d\fI level\fR"
33 /* Enable libmilter debugging at the specified level.
34 /* .IP "\fB-D\fI address\fR"
35 /* Delete the specified recipient address. Multiple -D options
36 /* are supported.
37 /* .IP "\fB-f \fIsender\fR"
38 /* Replace the sender by the specified address.
39 /* .IP "\fB-h \fI'index header-label header-value'\fR"
40 /* Replace the message header at the specified position.
41 /* .IP "\fB-i \fI'index header-label header-value'\fR"
42 /* Insert header at specified position.
43 /* .IP "\fB-l\fR"
44 /* Header values include leading space. Specify this option
45 /* before \fB-i\fR or \fB-h\fR.
46 /* .IP "\fB-m connect|helo|mail|rcpt|data|eoh|eom\fR"
47 /* The protocol stage that receives the list of macros specified
48 /* with \fB-M\fR. The default protocol stage is \fBconnect\fR.
49 /* .IP "\fB-M \fIset_macro_list\fR"
50 /* A non-default list of macros that the MTA should send at
51 /* the protocol stage specified with \fB-m\fR.
52 /* .IP "\fB-n connect|helo|mail|rcpt|data|header|eoh|body|eom|unknown\fR"
53 /* The event that the MTA should not send.
54 /* .IP "\fB-N connect|helo|mail|rcpt|data|header|eoh|body|eom|unknown\fR"
55 /* The event for which the filter will not reply.
56 /* .IP "\fB-p inet:\fIport\fB@\fIhost\fB|unix:\fIpathname\fR"
57 /* The mail filter listen endpoint.
58 /* .IP "\fB-r\fR"
59 /* Request rejected recipients from the MTA.
60 /* .IP "\fB-v\fR"
61 /* Make the program more verbose.
62 /* LICENSE
63 /* .ad
64 /* .fi
65 /* The Secure Mailer license must be distributed with this software.
66 /* AUTHOR(S)
67 /* Wietse Venema
68 /* IBM T.J. Watson Research
69 /* P.O. Box 704
70 /* Yorktown Heights, NY 10598, USA
71 /*
72 /* Wietse Venema
73 /* Google, Inc.
74 /* 111 8th Avenue
75 /* New York, NY 10011, USA
76 /*--*/
77 
78 #include <sys/types.h>
79 #include <sys/socket.h>
80 #include <netinet/in.h>
81 #include <sys/un.h>
82 #include <arpa/inet.h>
83 #include <errno.h>
84 #include <stdio.h>
85 #include <stdlib.h>
86 #include <unistd.h>
87 #include <string.h>
88 
89 #include "libmilter/mfapi.h"
90 #include "libmilter/mfdef.h"
91 
92 static int conn_count;
93 static int verbose;
94 
95 static int test_connect_reply = SMFIS_CONTINUE;
96 static int test_helo_reply = SMFIS_CONTINUE;
97 static int test_mail_reply = SMFIS_CONTINUE;
98 static int test_rcpt_reply = SMFIS_CONTINUE;
99 
100 #if SMFI_VERSION > 3
101 static int test_data_reply = SMFIS_CONTINUE;
102 
103 #endif
104 static int test_header_reply = SMFIS_CONTINUE;
105 static int test_eoh_reply = SMFIS_CONTINUE;
106 static int test_body_reply = SMFIS_CONTINUE;
107 static int test_eom_reply = SMFIS_CONTINUE;
108 
109 #if SMFI_VERSION > 2
110 static int test_unknown_reply = SMFIS_CONTINUE;
111 
112 #endif
113 static int test_close_reply = SMFIS_CONTINUE;
114 static int test_abort_reply = SMFIS_CONTINUE;
115 
116 struct command_map {
117  const char *name;
118  int *reply;
119 };
120 
121 static const struct command_map command_map[] = {
122  "connect", &test_connect_reply,
123  "helo", &test_helo_reply,
124  "mail", &test_mail_reply,
125  "rcpt", &test_rcpt_reply,
126  "header", &test_header_reply,
127  "eoh", &test_eoh_reply,
128  "body", &test_body_reply,
129  "eom", &test_eom_reply,
130  "abort", &test_abort_reply,
131  "close", &test_close_reply,
132 #if SMFI_VERSION > 2
133  "unknown", &test_unknown_reply,
134 #endif
135 #if SMFI_VERSION > 3
136  "data", &test_data_reply,
137 #endif
138  0, 0,
139 };
140 
141 static char *reply_code;
142 static char *reply_dsn;
143 static char *reply_message;
144 
145 #ifdef SMFIR_CHGFROM
146 static char *chg_from;
147 
148 #endif
149 
150 #ifdef SMFIR_INSHEADER
151 static char *ins_hdr;
152 static int ins_idx;
153 static char *ins_val;
154 
155 #endif
156 
157 #ifdef SMFIR_CHGHEADER
158 static char *chg_hdr;
159 static int chg_idx;
160 static char *chg_val;
161 
162 #endif
163 
164 #ifdef SMFIR_REPLBODY
165 static char *body_file;
166 
167 #endif
168 
169 #define MAX_RCPT 10
174 
175 static const char *macro_names[] = {
176  "_",
177  "i",
178  "j",
179  "v",
180  "{auth_authen}",
181  "{auth_author}",
182  "{auth_type}",
183  "{cert_issuer}",
184  "{cert_subject}",
185  "{cipher}",
186  "{cipher_bits}",
187  "{client_addr}",
188  "{client_connections}",
189  "{client_name}",
190  "{client_port}",
191  "{client_ptr}",
192  "{client_resolve}",
193  "{daemon_addr}",
194  "{daemon_name}",
195  "{daemon_port}",
196  "{if_addr}",
197  "{if_name}",
198  "{mail_addr}",
199  "{mail_host}",
200  "{mail_mailer}",
201  "{rcpt_addr}",
202  "{rcpt_host}",
203  "{rcpt_mailer}",
204  "{tls_version}",
205  0,
206 };
207 
208 static int test_reply(SMFICTX *ctx, int code)
209 {
210  const char **cpp;
211  const char *symval;
212 
213  for (cpp = macro_names; *cpp; cpp++)
214  if ((symval = smfi_getsymval(ctx, (char *) *cpp)) != 0)
215  printf("macro: %s=\"%s\"\n", *cpp, symval);
216  (void) fflush(stdout); /* In case output redirected. */
217 
218  if (code == SMFIR_REPLYCODE) {
219  if (smfi_setmlreply(ctx, reply_code, reply_dsn, reply_message, reply_message, (char *) 0) == MI_FAILURE)
220  fprintf(stderr, "smfi_setmlreply failed\n");
221  printf("test_reply %s\n", reply_code);
222  return (reply_code[0] == '4' ? SMFIS_TEMPFAIL : SMFIS_REJECT);
223  } else {
224  printf("test_reply %d\n\n", code);
225  return (code);
226  }
227 }
228 
229 static sfsistat test_connect(SMFICTX *ctx, char *name, struct sockaddr * sa)
230 {
231  const char *print_addr;
232  char buf[BUFSIZ];
233 
234  printf("test_connect %s ", name);
235  switch (sa->sa_family) {
236  case AF_INET:
237  {
238  struct sockaddr_in *sin = (struct sockaddr_in *) sa;
239 
240  print_addr = inet_ntop(AF_INET, &sin->sin_addr, buf, sizeof(buf));
241  if (print_addr == 0)
242  print_addr = strerror(errno);
243  printf("AF_INET (%s:%d)\n", print_addr, ntohs(sin->sin_port));
244  }
245  break;
246 #ifdef HAS_IPV6
247  case AF_INET6:
248  {
249  struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa;
250 
251  print_addr = inet_ntop(AF_INET, &sin6->sin6_addr, buf, sizeof(buf));
252  if (print_addr == 0)
253  print_addr = strerror(errno);
254  printf("AF_INET6 (%s:%d)\n", print_addr, ntohs(sin6->sin6_port));
255  }
256  break;
257 #endif
258  case AF_UNIX:
259  {
260 #undef sun
261  struct sockaddr_un *sun = (struct sockaddr_un *) sa;
262 
263  printf("AF_UNIX (%s)\n", sun->sun_path);
264  }
265  break;
266  default:
267  printf(" [unknown address family]\n");
268  break;
269  }
270  return (test_reply(ctx, test_connect_reply));
271 }
272 
273 static sfsistat test_helo(SMFICTX *ctx, char *arg)
274 {
275  printf("test_helo \"%s\"\n", arg ? arg : "NULL");
276  return (test_reply(ctx, test_helo_reply));
277 }
278 
279 static sfsistat test_mail(SMFICTX *ctx, char **argv)
280 {
281  char **cpp;
282 
283  printf("test_mail");
284  for (cpp = argv; *cpp; cpp++)
285  printf(" \"%s\"", *cpp);
286  printf("\n");
287  return (test_reply(ctx, test_mail_reply));
288 }
289 
290 static sfsistat test_rcpt(SMFICTX *ctx, char **argv)
291 {
292  char **cpp;
293 
294  printf("test_rcpt");
295  for (cpp = argv; *cpp; cpp++)
296  printf(" \"%s\"", *cpp);
297  printf("\n");
298  return (test_reply(ctx, test_rcpt_reply));
299 }
300 
301 
302 sfsistat test_header(SMFICTX *ctx, char *name, char *value)
303 {
304  printf("test_header \"%s\" \"%s\"\n", name, value);
305  return (test_reply(ctx, test_header_reply));
306 }
307 
308 static sfsistat test_eoh(SMFICTX *ctx)
309 {
310  printf("test_eoh\n");
311  return (test_reply(ctx, test_eoh_reply));
312 }
313 
314 static sfsistat test_body(SMFICTX *ctx, unsigned char *data, size_t data_len)
315 {
316  if (verbose == 0)
317  printf("test_body %ld bytes\n", (long) data_len);
318  else
319  printf("%.*s", (int) data_len, data);
320  return (test_reply(ctx, test_body_reply));
321 }
322 
323 static sfsistat test_eom(SMFICTX *ctx)
324 {
325  printf("test_eom\n");
326 #ifdef SMFIR_REPLBODY
327  if (body_file) {
328  char buf[BUFSIZ + 2];
329  FILE *fp;
330  size_t len;
331  int count;
332 
333  if ((fp = fopen(body_file, "r")) == 0) {
334  perror(body_file);
335  } else {
336  printf("replace body with content of %s\n", body_file);
337  for (count = 0; fgets(buf, BUFSIZ, fp) != 0; count++) {
338  len = strcspn(buf, "\n");
339  buf[len + 0] = '\r';
340  buf[len + 1] = '\n';
341  if (smfi_replacebody(ctx, buf, len + 2) == MI_FAILURE) {
342  fprintf(stderr, "body replace failure\n");
343  exit(1);
344  }
345  if (verbose)
346  printf("%.*s\n", (int) len, buf);
347  }
348  if (count == 0)
349  perror("fgets");
350  (void) fclose(fp);
351  }
352  }
353 #endif
354 #ifdef SMFIR_CHGFROM
355  if (chg_from != 0 && smfi_chgfrom(ctx, chg_from, "whatever") == MI_FAILURE)
356  fprintf(stderr, "smfi_chgfrom failed\n");
357 #endif
358 #ifdef SMFIR_INSHEADER
359  if (ins_hdr && smfi_insheader(ctx, ins_idx, ins_hdr, ins_val) == MI_FAILURE)
360  fprintf(stderr, "smfi_insheader failed\n");
361 #endif
362 #ifdef SMFIR_CHGHEADER
363  if (chg_hdr && smfi_chgheader(ctx, chg_hdr, chg_idx, chg_val) == MI_FAILURE)
364  fprintf(stderr, "smfi_chgheader failed\n");
365 #endif
366  {
367  int count;
368  char *args;
369 
370  for (count = 0; count < add_rcpt_count; count++) {
371  if ((args = strchr(add_rcpt[count], ' ')) != 0) {
372  *args++ = 0;
373  if (smfi_addrcpt_par(ctx, add_rcpt[count], args) == MI_FAILURE)
374  fprintf(stderr, "smfi_addrcpt_par `%s' `%s' failed\n",
375  add_rcpt[count], args);
376  } else {
377  if (smfi_addrcpt(ctx, add_rcpt[count]) == MI_FAILURE)
378  fprintf(stderr, "smfi_addrcpt `%s' failed\n",
379  add_rcpt[count]);
380  }
381  }
382 
383  for (count = 0; count < del_rcpt_count; count++)
384  if (smfi_delrcpt(ctx, del_rcpt[count]) == MI_FAILURE)
385  fprintf(stderr, "smfi_delrcpt `%s' failed\n", del_rcpt[count]);
386  }
387  return (test_reply(ctx, test_eom_reply));
388 }
389 
390 static sfsistat test_abort(SMFICTX *ctx)
391 {
392  printf("test_abort\n");
393  return (test_reply(ctx, test_abort_reply));
394 }
395 
396 static sfsistat test_close(SMFICTX *ctx)
397 {
398  printf("test_close\n");
399  if (verbose)
400  printf("conn_count %d\n", conn_count);
401  if (conn_count > 0 && --conn_count == 0)
402  exit(0);
403  return (test_reply(ctx, test_close_reply));
404 }
405 
406 #if SMFI_VERSION > 3
407 
408 static sfsistat test_data(SMFICTX *ctx)
409 {
410  printf("test_data\n");
411  return (test_reply(ctx, test_data_reply));
412 }
413 
414 #endif
415 
416 #if SMFI_VERSION > 2
417 
418 static sfsistat test_unknown(SMFICTX *ctx, const char *what)
419 {
420  printf("test_unknown %s\n", what);
421  return (test_reply(ctx, test_unknown_reply));
422 }
423 
424 #endif
425 
426 #if SMFI_VERSION > 5
427 
428 static sfsistat test_negotiate(SMFICTX *, unsigned long, unsigned long,
429  unsigned long, unsigned long,
430  unsigned long *, unsigned long *,
431  unsigned long *, unsigned long *);
432 
433 #endif
434 
435 #ifndef SMFIF_CHGFROM
436 #define SMFIF_CHGFROM 0
437 #endif
438 #ifndef SMFIP_HDR_LEADSPC
439 #define SMFIP_HDR_LEADSPC 0
440 #define misc_mask 0
441 #endif
442 
443 static struct smfiDesc smfilter =
444 {
445  "test-milter",
446  SMFI_VERSION,
448  test_connect,
449  test_helo,
450  test_mail,
451  test_rcpt,
452  test_header,
453  test_eoh,
454  test_body,
455  test_eom,
456  test_abort,
457  test_close,
458 #if SMFI_VERSION > 2
459  test_unknown,
460 #endif
461 #if SMFI_VERSION > 3
462  test_data,
463 #endif
464 #if SMFI_VERSION > 5
465  test_negotiate,
466 #endif
467 };
468 
469 #if SMFI_VERSION > 5
470 
471 static const char *macro_states[] = {
472  "connect", /* SMFIM_CONNECT */
473  "helo", /* SMFIM_HELO */
474  "mail", /* SMFIM_ENVFROM */
475  "rcpt", /* SMFIM_ENVRCPT */
476  "data", /* SMFIM_DATA */
477  "eom", /* SMFIM_EOM < SMFIM_EOH */
478  "eoh", /* SMFIM_EOH > SMFIM_EOM */
479  0,
480 };
481 
482 static int set_macro_state;
483 static char *set_macro_list;
484 
485 typedef sfsistat (*FILTER_ACTION) ();
486 
487 struct noproto_map {
488  const char *name;
489  int send_mask;
490  int reply_mask;
491  int *reply;
492  FILTER_ACTION *action;
493 };
494 
495 static const struct noproto_map noproto_map[] = {
496  "connect", SMFIP_NOCONNECT, SMFIP_NR_CONN, &test_connect_reply, &smfilter.xxfi_connect,
497  "helo", SMFIP_NOHELO, SMFIP_NR_HELO, &test_helo_reply, &smfilter.xxfi_helo,
498  "mail", SMFIP_NOMAIL, SMFIP_NR_MAIL, &test_mail_reply, &smfilter.xxfi_envfrom,
499  "rcpt", SMFIP_NORCPT, SMFIP_NR_RCPT, &test_rcpt_reply, &smfilter.xxfi_envrcpt,
500  "data", SMFIP_NODATA, SMFIP_NR_DATA, &test_data_reply, &smfilter.xxfi_data,
501  "header", SMFIP_NOHDRS, SMFIP_NR_HDR, &test_header_reply, &smfilter.xxfi_header,
502  "eoh", SMFIP_NOEOH, SMFIP_NR_EOH, &test_eoh_reply, &smfilter.xxfi_eoh,
503  "body", SMFIP_NOBODY, SMFIP_NR_BODY, &test_body_reply, &smfilter.xxfi_body,
504  "unknown", SMFIP_NOUNKNOWN, SMFIP_NR_UNKN, &test_connect_reply, &smfilter.xxfi_unknown,
505  0,
506 };
507 
508 static int nosend_mask;
509 static int noreply_mask;
510 static int misc_mask;
511 
512 static sfsistat test_negotiate(SMFICTX *ctx,
513  unsigned long f0,
514  unsigned long f1,
515  unsigned long f2,
516  unsigned long f3,
517  unsigned long *pf0,
518  unsigned long *pf1,
519  unsigned long *pf2,
520  unsigned long *pf3)
521 {
522  if (set_macro_list) {
523  if (verbose)
524  printf("set symbol list %s to \"%s\"\n",
525  macro_states[set_macro_state], set_macro_list);
526  smfi_setsymlist(ctx, set_macro_state, set_macro_list);
527  }
528  if (verbose)
529  printf("negotiate f0=%lx *pf0 = %lx f1=%lx *pf1=%lx nosend=%lx noreply=%lx misc=%lx\n",
530  f0, *pf0, f1, *pf1, (long) nosend_mask, (long) noreply_mask, (long) misc_mask);
531  *pf0 = f0;
532  *pf1 = f1 & (nosend_mask | noreply_mask | misc_mask);
533  return (SMFIS_CONTINUE);
534 }
535 
536 #endif
537 
538 static void parse_hdr_info(const char *optarg, int *idx,
539  char **hdr, char **value)
540 {
541  int len;
542 
543  len = strlen(optarg) + 1;
544  if ((*hdr = malloc(len)) == 0 || (*value = malloc(len)) == 0) {
545  fprintf(stderr, "out of memory\n");
546  exit(1);
547  }
548  if ((misc_mask & SMFIP_HDR_LEADSPC) == 0 ?
549  sscanf(optarg, "%d %s %[^\n]", idx, *hdr, *value) != 3 :
550  sscanf(optarg, "%d %[^ ]%[^\n]", idx, *hdr, *value) != 3) {
551  fprintf(stderr, "bad header info: %s\n", optarg);
552  exit(1);
553  }
554 }
555 
556 int main(int argc, char **argv)
557 {
558  char *action = 0;
559  char *command = 0;
560  const struct command_map *cp;
561  int ch;
562  int code;
563  const char **cpp;
564  char *set_macro_state_arg = 0;
565  char *nosend = 0;
566  char *noreply = 0;
567  const struct noproto_map *np;
568 
569  while ((ch = getopt(argc, argv, "a:A:b:c:C:d:D:f:h:i:lm:M:n:N:p:rv")) > 0) {
570  switch (ch) {
571  case 'a':
572  action = optarg;
573  break;
574  case 'A':
575  if (add_rcpt_count >= MAX_RCPT) {
576  fprintf(stderr, "too many -A options\n");
577  exit(1);
578  }
579  add_rcpt[add_rcpt_count++] = optarg;
580  break;
581  case 'b':
582 #ifdef SMFIR_REPLBODY
583  if (body_file) {
584  fprintf(stderr, "too many -b options\n");
585  exit(1);
586  }
587  body_file = optarg;
588 #else
589  fprintf(stderr, "no libmilter support to replace body\n");
590 #endif
591  break;
592  case 'c':
593  command = optarg;
594  break;
595  case 'd':
596  if (smfi_setdbg(atoi(optarg)) == MI_FAILURE) {
597  fprintf(stderr, "smfi_setdbg failed\n");
598  exit(1);
599  }
600  break;
601  case 'D':
602  if (del_rcpt_count >= MAX_RCPT) {
603  fprintf(stderr, "too many -D options\n");
604  exit(1);
605  }
606  del_rcpt[del_rcpt_count++] = optarg;
607  break;
608  case 'f':
609 #ifdef SMFIR_CHGFROM
610  if (chg_from) {
611  fprintf(stderr, "too many -f options\n");
612  exit(1);
613  }
614  chg_from = optarg;
615 #else
616  fprintf(stderr, "no libmilter support to change sender\n");
617  exit(1);
618 #endif
619  break;
620  case 'h':
621 #ifdef SMFIR_CHGHEADER
622  if (chg_hdr) {
623  fprintf(stderr, "too many -h options\n");
624  exit(1);
625  }
626  parse_hdr_info(optarg, &chg_idx, &chg_hdr, &chg_val);
627 #else
628  fprintf(stderr, "no libmilter support to change header\n");
629  exit(1);
630 #endif
631  break;
632  case 'i':
633 #ifdef SMFIR_INSHEADER
634  if (ins_hdr) {
635  fprintf(stderr, "too many -i options\n");
636  exit(1);
637  }
638  parse_hdr_info(optarg, &ins_idx, &ins_hdr, &ins_val);
639 #else
640  fprintf(stderr, "no libmilter support to insert header\n");
641  exit(1);
642 #endif
643  break;
644  case 'l':
645 #if SMFI_VERSION > 5
646  if (ins_hdr || chg_hdr) {
647  fprintf(stderr, "specify -l before -i or -r\n");
648  exit(1);
649  }
650  misc_mask |= SMFIP_HDR_LEADSPC;
651 #else
652  fprintf(stderr, "no libmilter support for leading space\n");
653  exit(1);
654 #endif
655  break;
656  case 'm':
657 #if SMFI_VERSION > 5
658  if (set_macro_state_arg) {
659  fprintf(stderr, "too many -m options\n");
660  exit(1);
661  }
662  set_macro_state_arg = optarg;
663 #else
664  fprintf(stderr, "no libmilter support to specify macro list\n");
665  exit(1);
666 #endif
667  break;
668  case 'M':
669 #if SMFI_VERSION > 5
670  if (set_macro_list) {
671  fprintf(stderr, "too many -M options\n");
672  exit(1);
673  }
674  set_macro_list = optarg;
675 #else
676  fprintf(stderr, "no libmilter support to specify macro list\n");
677 #endif
678  break;
679  case 'n':
680 #if SMFI_VERSION > 5
681  if (nosend) {
682  fprintf(stderr, "too many -n options\n");
683  exit(1);
684  }
685  nosend = optarg;
686 #else
687  fprintf(stderr, "no libmilter support for negotiate callback\n");
688 #endif
689  break;
690  case 'N':
691 #if SMFI_VERSION > 5
692  if (noreply) {
693  fprintf(stderr, "too many -n options\n");
694  exit(1);
695  }
696  noreply = optarg;
697 #else
698  fprintf(stderr, "no libmilter support for negotiate callback\n");
699 #endif
700  break;
701  case 'p':
702  if (smfi_setconn(optarg) == MI_FAILURE) {
703  fprintf(stderr, "smfi_setconn failed\n");
704  exit(1);
705  }
706  break;
707  case 'r':
708 #ifdef SMFIP_RCPT_REJ
709  misc_mask |= SMFIP_RCPT_REJ;
710 #else
711  fprintf(stderr, "no libmilter support for rejected recipients\n");
712 #endif
713  break;
714  case 'v':
715  verbose++;
716  break;
717  case 'C':
718  conn_count = atoi(optarg);
719  break;
720  default:
721  fprintf(stderr,
722  "usage: %s [-dv] \n"
723  "\t[-a action] non-default action\n"
724  "\t[-b body_text] replace body\n"
725  "\t[-c command] non-default action trigger\n"
726  "\t[-h 'index label value'] replace header\n"
727  "\t[-i 'index label value'] insert header\n"
728  "\t[-m macro_state] non-default macro state\n"
729  "\t[-M macro_list] non-default macro list\n"
730  "\t[-n events] don't receive these events\n"
731  "\t[-N events] don't reply to these events\n"
732  "\t-p port milter application\n"
733  "\t-r request rejected recipients\n"
734  "\t[-C conn_count] when to exit\n",
735  argv[0]);
736  exit(1);
737  }
738  }
739  if (command) {
740  for (cp = command_map; /* see below */ ; cp++) {
741  if (cp->name == 0) {
742  fprintf(stderr, "bad -c argument: %s\n", command);
743  exit(1);
744  }
745  if (strcmp(command, cp->name) == 0)
746  break;
747  }
748  }
749  if (action) {
750  if (command == 0)
751  cp = command_map;
752  if (strcmp(action, "tempfail") == 0) {
753  cp->reply[0] = SMFIS_TEMPFAIL;
754  } else if (strcmp(action, "reject") == 0) {
755  cp->reply[0] = SMFIS_REJECT;
756  } else if (strcmp(action, "accept") == 0) {
757  cp->reply[0] = SMFIS_ACCEPT;
758  } else if (strcmp(action, "discard") == 0) {
759  cp->reply[0] = SMFIS_DISCARD;
760 #ifdef SMFIS_SKIP
761  } else if (strcmp(action, "skip") == 0) {
762  cp->reply[0] = SMFIS_SKIP;
763 #endif
764  } else if ((code = atoi(action)) >= 400
765  && code <= 599
766  && action[3] == ' ') {
767  cp->reply[0] = SMFIR_REPLYCODE;
768  reply_code = action;
769  reply_dsn = action + 3;
770  if (*reply_dsn != 0) {
771  *reply_dsn++ = 0;
772  reply_dsn += strspn(reply_dsn, " ");
773  }
774  if (*reply_dsn == 0) {
775  reply_dsn = reply_message = 0;
776  } else {
777  reply_message = reply_dsn + strcspn(reply_dsn, " ");
778  if (*reply_message != 0) {
779  *reply_message++ = 0;
780  reply_message += strspn(reply_message, " ");
781  }
782  if (*reply_message == 0)
783  reply_message = 0;
784  }
785  } else {
786  fprintf(stderr, "bad -a argument: %s\n", action);
787  exit(1);
788  }
789  if (verbose) {
790  printf("command %s action %d\n", cp->name, cp->reply[0]);
791  if (reply_code)
792  printf("reply code %s dsn %s message %s\n",
793  reply_code, reply_dsn ? reply_dsn : "(null)",
794  reply_message ? reply_message : "(null)");
795  }
796  }
797 #if SMFI_VERSION > 5
798  if (set_macro_state_arg) {
799  for (cpp = macro_states; /* see below */ ; cpp++) {
800  if (*cpp == 0) {
801  fprintf(stderr, "bad -m argument: %s\n", set_macro_state_arg);
802  exit(1);
803  }
804  if (strcmp(set_macro_state_arg, *cpp) == 0)
805  break;
806  }
807  set_macro_state = cpp - macro_states;
808  }
809  if (nosend) {
810  for (np = noproto_map; /* see below */ ; np++) {
811  if (np->name == 0) {
812  fprintf(stderr, "bad -n argument: %s\n", nosend);
813  exit(1);
814  }
815  if (strcmp(nosend, np->name) == 0)
816  break;
817  }
818  nosend_mask = np->send_mask;
819  np->action[0] = 0;
820  }
821  if (noreply) {
822  for (np = noproto_map; /* see below */ ; np++) {
823  if (np->name == 0) {
824  fprintf(stderr, "bad -N argument: %s\n", noreply);
825  exit(1);
826  }
827  if (strcmp(noreply, np->name) == 0)
828  break;
829  }
830  noreply_mask = np->reply_mask;
831  *np->reply = SMFIS_NOREPLY;
832  }
833 #endif
834  if (smfi_register(smfilter) == MI_FAILURE) {
835  fprintf(stderr, "smfi_register failed\n");
836  exit(1);
837  }
838  return (smfi_main());
839 }
sfsistat test_header(SMFICTX *ctx, char *name, char *value)
Definition: test-milter.c:302
const char * name
Definition: test-milter.c:117
#define SMFIP_NR_BODY
Definition: milter8.c:226
#define SMFIP_NR_HELO
Definition: milter8.c:220
#define SMFIP_NR_EOH
Definition: milter8.c:225
#define SMFIP_NOMAIL
Definition: milter8.c:207
int main(int argc, char **argv)
Definition: test-milter.c:556
#define SMFIR_REPLYCODE
Definition: milter8.c:168
#define SMFIP_NR_HDR
Definition: milter8.c:212
#define SMFIP_NOUNKNOWN
Definition: milter8.c:214
char * del_rcpt[MAX_RCPT]
Definition: test-milter.c:173
#define SMFIP_NOHELO
Definition: milter8.c:206
#define SMFIP_NOBODY
Definition: milter8.c:209
#define SMFIF_ADDRCPT
Definition: milter8.c:271
char * add_rcpt[MAX_RCPT]
Definition: test-milter.c:171
#define misc_mask
Definition: test-milter.c:440
#define SMFIP_NOCONNECT
Definition: milter8.c:205
#define SMFIF_CHGHDRS
Definition: milter8.c:273
const char * inet_ntop(int af, const void *src, char *dst, SOCKADDR_SIZE size)
Definition: sys_compat.c:325
#define MAX_RCPT
Definition: test-milter.c:169
#define SMFIP_RCPT_REJ
Definition: milter8.c:218
#define SMFIP_NORCPT
Definition: milter8.c:208
#define SMFIP_NR_RCPT
Definition: milter8.c:222
#define SMFIP_NR_CONN
Definition: milter8.c:219
#define SMFIP_NODATA
Definition: milter8.c:215
#define SMFIF_ADDHDRS
Definition: milter8.c:269
int del_rcpt_count
Definition: test-milter.c:172
#define SMFIF_CHGFROM
Definition: test-milter.c:436
#define SMFIP_NOHDRS
Definition: milter8.c:210
#define SMFIP_NR_UNKN
Definition: milter8.c:224
#define SMFIP_HDR_LEADSPC
Definition: test-milter.c:439
#define SMFIP_NR_DATA
Definition: milter8.c:223
#define SMFIP_NOEOH
Definition: milter8.c:211
#define SMFIF_CHGBODY
Definition: milter8.c:270
#define SMFIF_DELRCPT
Definition: milter8.c:272
int add_rcpt_count
Definition: test-milter.c:170
#define SMFIP_NR_MAIL
Definition: milter8.c:221