78 #include <sys/types.h> 
   79 #include <sys/socket.h> 
   80 #include <netinet/in.h> 
   82 #include <arpa/inet.h> 
   89 #include "libmilter/mfapi.h" 
   90 #include "libmilter/mfdef.h" 
   92 static int conn_count;
 
   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;
 
  101 static int test_data_reply = SMFIS_CONTINUE;
 
  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;
 
  110 static int test_unknown_reply = SMFIS_CONTINUE;
 
  113 static int test_close_reply = SMFIS_CONTINUE;
 
  114 static int test_abort_reply = SMFIS_CONTINUE;
 
  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,
 
  133     "unknown", &test_unknown_reply,
 
  136     "data", &test_data_reply,
 
  141 static char *reply_code;
 
  142 static char *reply_dsn;
 
  143 static char *reply_message;
 
  146 static char *chg_from;
 
  150 #ifdef SMFIR_INSHEADER 
  151 static char *ins_hdr;
 
  153 static char *ins_val;
 
  157 #ifdef SMFIR_CHGHEADER 
  158 static char *chg_hdr;
 
  160 static char *chg_val;
 
  164 #ifdef SMFIR_REPLBODY 
  165 static char *body_file;
 
  175 static const char *macro_names[] = {
 
  188     "{client_connections}",
 
  208 static int test_reply(SMFICTX *ctx, 
int code)
 
  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);          
 
  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);
 
  224     printf(
"test_reply %d\n\n", code);
 
  229 static sfsistat test_connect(SMFICTX *ctx, 
char *
name, 
struct sockaddr * sa)
 
  231     const char *print_addr;
 
  234     printf(
"test_connect %s ", name);
 
  235     switch (sa->sa_family) {
 
  238         struct sockaddr_in *sin = (
struct sockaddr_in *) sa;
 
  240         print_addr = 
inet_ntop(AF_INET, &sin->sin_addr, buf, 
sizeof(buf));
 
  242         print_addr = strerror(errno);
 
  243         printf(
"AF_INET (%s:%d)\n", print_addr, ntohs(sin->sin_port));
 
  249         struct sockaddr_in6 *sin6 = (
struct sockaddr_in6 *) sa;
 
  251         print_addr = 
inet_ntop(AF_INET, &sin6->sin6_addr, buf, 
sizeof(buf));
 
  253         print_addr = strerror(errno);
 
  254         printf(
"AF_INET6 (%s:%d)\n", print_addr, ntohs(sin6->sin6_port));
 
  261         struct sockaddr_un *sun = (
struct sockaddr_un *) sa;
 
  263         printf(
"AF_UNIX (%s)\n", sun->sun_path);
 
  267     printf(
" [unknown address family]\n");
 
  270     return (test_reply(ctx, test_connect_reply));
 
  273 static sfsistat test_helo(SMFICTX *ctx, 
char *arg)
 
  275     printf(
"test_helo \"%s\"\n", arg ? arg : 
"NULL");
 
  276     return (test_reply(ctx, test_helo_reply));
 
  279 static sfsistat test_mail(SMFICTX *ctx, 
char **argv)
 
  284     for (cpp = argv; *cpp; cpp++)
 
  285     printf(
" \"%s\"", *cpp);
 
  287     return (test_reply(ctx, test_mail_reply));
 
  290 static sfsistat test_rcpt(SMFICTX *ctx, 
char **argv)
 
  295     for (cpp = argv; *cpp; cpp++)
 
  296     printf(
" \"%s\"", *cpp);
 
  298     return (test_reply(ctx, test_rcpt_reply));
 
  304     printf(
"test_header \"%s\" \"%s\"\n", name, value);
 
  305     return (test_reply(ctx, test_header_reply));
 
  308 static sfsistat test_eoh(SMFICTX *ctx)
 
  310     printf(
"test_eoh\n");
 
  311     return (test_reply(ctx, test_eoh_reply));
 
  314 static sfsistat test_body(SMFICTX *ctx, 
unsigned char *data, 
size_t data_len)
 
  317     printf(
"test_body %ld bytes\n", (
long) data_len);
 
  319     printf(
"%.*s", (
int) data_len, data);
 
  320     return (test_reply(ctx, test_body_reply));
 
  323 static sfsistat test_eom(SMFICTX *ctx)
 
  325     printf(
"test_eom\n");
 
  326 #ifdef SMFIR_REPLBODY 
  328     char    buf[BUFSIZ + 2];
 
  333     if ((fp = fopen(body_file, 
"r")) == 0) {
 
  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");
 
  341         if (smfi_replacebody(ctx, buf, len + 2) == MI_FAILURE) {
 
  342             fprintf(stderr, 
"body replace failure\n");
 
  346             printf(
"%.*s\n", (
int) len, buf);
 
  355     if (chg_from != 0 && smfi_chgfrom(ctx, chg_from, 
"whatever") == MI_FAILURE)
 
  356     fprintf(stderr, 
"smfi_chgfrom failed\n");
 
  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");
 
  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");
 
  371         if ((args = strchr(
add_rcpt[count], 
' ')) != 0) {
 
  373         if (smfi_addrcpt_par(ctx, 
add_rcpt[count], args) == MI_FAILURE)
 
  374             fprintf(stderr, 
"smfi_addrcpt_par `%s' `%s' failed\n",
 
  377         if (smfi_addrcpt(ctx, 
add_rcpt[count]) == MI_FAILURE)
 
  378             fprintf(stderr, 
"smfi_addrcpt `%s' failed\n",
 
  384         if (smfi_delrcpt(ctx, 
del_rcpt[count]) == MI_FAILURE)
 
  385         fprintf(stderr, 
"smfi_delrcpt `%s' failed\n", 
del_rcpt[count]);
 
  387     return (test_reply(ctx, test_eom_reply));
 
  390 static sfsistat test_abort(SMFICTX *ctx)
 
  392     printf(
"test_abort\n");
 
  393     return (test_reply(ctx, test_abort_reply));
 
  396 static sfsistat test_close(SMFICTX *ctx)
 
  398     printf(
"test_close\n");
 
  400     printf(
"conn_count %d\n", conn_count);
 
  401     if (conn_count > 0 && --conn_count == 0)
 
  403     return (test_reply(ctx, test_close_reply));
 
  408 static sfsistat test_data(SMFICTX *ctx)
 
  410     printf(
"test_data\n");
 
  411     return (test_reply(ctx, test_data_reply));
 
  418 static sfsistat test_unknown(SMFICTX *ctx, 
const char *what)
 
  420     printf(
"test_unknown %s\n", what);
 
  421     return (test_reply(ctx, test_unknown_reply));
 
  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 *);
 
  435 #ifndef SMFIF_CHGFROM 
  436 #define SMFIF_CHGFROM 0 
  438 #ifndef SMFIP_HDR_LEADSPC 
  439 #define SMFIP_HDR_LEADSPC 0 
  443 static struct smfiDesc smfilter =
 
  471 static const char *macro_states[] = {
 
  482 static int set_macro_state;
 
  483 static char *set_macro_list;
 
  485 typedef sfsistat (*FILTER_ACTION) ();
 
  492     FILTER_ACTION *action;
 
  495 static const struct noproto_map noproto_map[] = {
 
  508 static int nosend_mask;
 
  509 static int noreply_mask;
 
  512 static sfsistat test_negotiate(SMFICTX *ctx,
 
  522     if (set_macro_list) {
 
  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);
 
  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);
 
  532     *pf1 = f1 & (nosend_mask | noreply_mask | 
misc_mask);
 
  533     return (SMFIS_CONTINUE);
 
  538 static void parse_hdr_info(
const char *optarg, 
int *idx,
 
  539                        char **hdr, 
char **value)
 
  543     len = strlen(optarg) + 1;
 
  544     if ((*hdr = malloc(len)) == 0 || (*value = malloc(len)) == 0) {
 
  545     fprintf(stderr, 
"out of memory\n");
 
  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);
 
  556 int     main(
int argc, 
char **argv)
 
  560     const struct command_map *cp;
 
  564     char   *set_macro_state_arg = 0;
 
  567     const struct noproto_map *np;
 
  569     while ((ch = getopt(argc, argv, 
"a:A:b:c:C:d:D:f:h:i:lm:M:n:N:p:rv")) > 0) {
 
  576         fprintf(stderr, 
"too many -A options\n");
 
  579         add_rcpt[add_rcpt_count++] = optarg;
 
  582 #ifdef SMFIR_REPLBODY 
  584         fprintf(stderr, 
"too many -b options\n");
 
  589         fprintf(stderr, 
"no libmilter support to replace body\n");
 
  596         if (smfi_setdbg(atoi(optarg)) == MI_FAILURE) {
 
  597         fprintf(stderr, 
"smfi_setdbg failed\n");
 
  603         fprintf(stderr, 
"too many -D options\n");
 
  606         del_rcpt[del_rcpt_count++] = optarg;
 
  611         fprintf(stderr, 
"too many -f options\n");
 
  616         fprintf(stderr, 
"no libmilter support to change sender\n");
 
  621 #ifdef SMFIR_CHGHEADER 
  623         fprintf(stderr, 
"too many -h options\n");
 
  626         parse_hdr_info(optarg, &chg_idx, &chg_hdr, &chg_val);
 
  628         fprintf(stderr, 
"no libmilter support to change header\n");
 
  633 #ifdef SMFIR_INSHEADER 
  635         fprintf(stderr, 
"too many -i options\n");
 
  638         parse_hdr_info(optarg, &ins_idx, &ins_hdr, &ins_val);
 
  640         fprintf(stderr, 
"no libmilter support to insert header\n");
 
  646         if (ins_hdr || chg_hdr) {
 
  647         fprintf(stderr, 
"specify -l before -i or -r\n");
 
  652         fprintf(stderr, 
"no libmilter support for leading space\n");
 
  658         if (set_macro_state_arg) {
 
  659         fprintf(stderr, 
"too many -m options\n");
 
  662         set_macro_state_arg = optarg;
 
  664         fprintf(stderr, 
"no libmilter support to specify macro list\n");
 
  670         if (set_macro_list) {
 
  671         fprintf(stderr, 
"too many -M options\n");
 
  674         set_macro_list = optarg;
 
  676         fprintf(stderr, 
"no libmilter support to specify macro list\n");
 
  682         fprintf(stderr, 
"too many -n options\n");
 
  687         fprintf(stderr, 
"no libmilter support for negotiate callback\n");
 
  693         fprintf(stderr, 
"too many -n options\n");
 
  698         fprintf(stderr, 
"no libmilter support for negotiate callback\n");
 
  702         if (smfi_setconn(optarg) == MI_FAILURE) {
 
  703         fprintf(stderr, 
"smfi_setconn failed\n");
 
  708 #ifdef SMFIP_RCPT_REJ 
  711         fprintf(stderr, 
"no libmilter support for rejected recipients\n");
 
  718         conn_count = atoi(optarg);
 
  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",
 
  740     for (cp = command_map;  ; cp++) {
 
  742         fprintf(stderr, 
"bad -c argument: %s\n", command);
 
  745         if (strcmp(command, cp->
name) == 0)
 
  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;
 
  761     } 
else if (strcmp(action, 
"skip") == 0) {
 
  762         cp->
reply[0] = SMFIS_SKIP;
 
  764     } 
else if ((code = atoi(action)) >= 400
 
  766            && action[3] == 
' ') {
 
  769         reply_dsn = action + 3;
 
  770         if (*reply_dsn != 0) {
 
  772         reply_dsn += strspn(reply_dsn, 
" ");
 
  774         if (*reply_dsn == 0) {
 
  775         reply_dsn = reply_message = 0;
 
  777         reply_message = reply_dsn + strcspn(reply_dsn, 
" ");
 
  778         if (*reply_message != 0) {
 
  779             *reply_message++ = 0;
 
  780             reply_message += strspn(reply_message, 
" ");
 
  782         if (*reply_message == 0)
 
  786         fprintf(stderr, 
"bad -a argument: %s\n", action);
 
  790         printf(
"command %s action %d\n", cp->
name, cp->
reply[0]);
 
  792         printf(
"reply code %s dsn %s message %s\n",
 
  793                reply_code, reply_dsn ? reply_dsn : 
"(null)",
 
  794                reply_message ? reply_message : 
"(null)");
 
  798     if (set_macro_state_arg) {
 
  799     for (cpp = macro_states;  ; cpp++) {
 
  801         fprintf(stderr, 
"bad -m argument: %s\n", set_macro_state_arg);
 
  804         if (strcmp(set_macro_state_arg, *cpp) == 0)
 
  807     set_macro_state = cpp - macro_states;
 
  810     for (np = noproto_map;  ; np++) {
 
  812         fprintf(stderr, 
"bad -n argument: %s\n", nosend);
 
  815         if (strcmp(nosend, np->name) == 0)
 
  818     nosend_mask = np->send_mask;
 
  822     for (np = noproto_map;  ; np++) {
 
  824         fprintf(stderr, 
"bad -N argument: %s\n", noreply);
 
  827         if (strcmp(noreply, np->name) == 0)
 
  830     noreply_mask = np->reply_mask;
 
  831     *np->reply = SMFIS_NOREPLY;
 
  834     if (smfi_register(smfilter) == MI_FAILURE) {
 
  835     fprintf(stderr, 
"smfi_register failed\n");
 
  838     return (smfi_main());
 
sfsistat test_header(SMFICTX *ctx, char *name, char *value)
 
int main(int argc, char **argv)
 
char * del_rcpt[MAX_RCPT]
 
char * add_rcpt[MAX_RCPT]
 
const char * inet_ntop(int af, const void *src, char *dst, SOCKADDR_SIZE size)
 
#define SMFIP_HDR_LEADSPC