int main (int argc, char *argv[]) { gint status = MI_SUCCESS; GError *error = NULL; GOptionContext *option_context; unsigned int major, minor, patch_level; #ifdef HAVE_LOCALE_H setlocale(LC_ALL, ""); #endif /* * workaround for memory profiler for GLib memory * profiler, we need to call g_mem_set_vtable prior to * any other GLib functions. smfi_version() calls * g_mem_set_vtable() internally. */ smfi_version(&major, &minor, &patch_level); option_context = g_option_context_new(NULL); g_option_context_add_main_entries(option_context, option_entries, NULL); if (!g_option_context_parse(option_context, &argc, &argv, &error)) { g_print("%s\n", error->message); g_error_free(error); g_option_context_free(option_context); exit(EXIT_FAILURE); } if (verbose) smfi_setdbg(6); status = smfi_setconn(spec); if (status == MI_SUCCESS) status = smfi_register(smfilter); if (status == MI_SUCCESS) return smfi_main() == MI_SUCCESS ? EXIT_SUCCESS : EXIT_FAILURE; return EXIT_FAILURE; }
int main(int argc, char **argv) { char *action = 0; char *command = 0; const struct command_map *cp; int ch; int code; const char **cpp; char *set_macro_state_arg = 0; char *nosend = 0; char *noreply = 0; const struct noproto_map *np; while ((ch = getopt(argc, argv, "a:A:b:c:C:d:f:h:i:lm:M:n:N:p:rv")) > 0) { switch (ch) { case 'a': action = optarg; break; case 'A': if (rcpt_count >= MAX_RCPT) { fprintf(stderr, "too many -A options\n"); exit(1); } rcpt_addr[rcpt_count++] = optarg; break; case 'b': #ifdef SMFIR_REPLBODY if (body_file) { fprintf(stderr, "too many -b options\n"); exit(1); } body_file = optarg; #else fprintf(stderr, "no libmilter support to replace body\n"); #endif break; case 'c': command = optarg; break; case 'd': if (smfi_setdbg(atoi(optarg)) == MI_FAILURE) { fprintf(stderr, "smfi_setdbg failed\n"); exit(1); } break; case 'f': #ifdef SMFIR_CHGFROM if (chg_from) { fprintf(stderr, "too many -f options\n"); exit(1); } chg_from = optarg; #else fprintf(stderr, "no libmilter support to change sender\n"); exit(1); #endif break; case 'h': #ifdef SMFIR_CHGHEADER if (chg_hdr) { fprintf(stderr, "too many -h options\n"); exit(1); } parse_hdr_info(optarg, &chg_idx, &chg_hdr, &chg_val); #else fprintf(stderr, "no libmilter support to change header\n"); exit(1); #endif break; case 'i': #ifdef SMFIR_INSHEADER if (ins_hdr) { fprintf(stderr, "too many -i options\n"); exit(1); } parse_hdr_info(optarg, &ins_idx, &ins_hdr, &ins_val); #else fprintf(stderr, "no libmilter support to insert header\n"); exit(1); #endif break; case 'l': #if SMFI_VERSION > 5 if (ins_hdr || chg_hdr) { fprintf(stderr, "specify -l before -i or -r\n"); exit(1); } misc_mask |= SMFIP_HDR_LEADSPC; #else fprintf(stderr, "no libmilter support for leading space\n"); exit(1); #endif break; case 'm': #if SMFI_VERSION > 5 if (set_macro_state_arg) { fprintf(stderr, "too many -m options\n"); exit(1); } set_macro_state_arg = optarg; #else fprintf(stderr, "no libmilter support to specify macro list\n"); exit(1); #endif break; case 'M': #if SMFI_VERSION > 5 if (set_macro_list) { fprintf(stderr, "too many -M options\n"); exit(1); } set_macro_list = optarg; #else fprintf(stderr, "no libmilter support to specify macro list\n"); #endif break; case 'n': #if SMFI_VERSION > 5 if (nosend) { fprintf(stderr, "too many -n options\n"); exit(1); } nosend = optarg; #else fprintf(stderr, "no libmilter support for negotiate callback\n"); #endif break; case 'N': #if SMFI_VERSION > 5 if (noreply) { fprintf(stderr, "too many -n options\n"); exit(1); } noreply = optarg; #else fprintf(stderr, "no libmilter support for negotiate callback\n"); #endif break; case 'p': if (smfi_setconn(optarg) == MI_FAILURE) { fprintf(stderr, "smfi_setconn failed\n"); exit(1); } break; case 'r': #ifdef SMFIP_RCPT_REJ misc_mask |= SMFIP_RCPT_REJ; #else fprintf(stderr, "no libmilter support for rejected recipients\n"); #endif break; case 'v': verbose++; break; case 'C': conn_count = atoi(optarg); break; default: fprintf(stderr, "usage: %s [-dv] \n" "\t[-a action] non-default action\n" "\t[-b body_text] replace body\n", "\t[-c command] non-default action trigger\n" "\t[-h 'index label value'] replace header\n" "\t[-i 'index label value'] insert header\n" "\t[-m macro_state] non-default macro state\n" "\t[-M macro_list] non-default macro list\n" "\t[-n events] don't receive these events\n" "\t[-N events] don't reply to these events\n" "\t-p port milter application\n" "\t-r request rejected recipients\n" "\t[-C conn_count] when to exit\n", argv[0]); exit(1); } } if (command) { for (cp = command_map; /* see below */ ; cp++) { if (cp->name == 0) { fprintf(stderr, "bad -c argument: %s\n", command); exit(1); } if (strcmp(command, cp->name) == 0) break; } } if (action) { if (command == 0) cp = command_map; if (strcmp(action, "tempfail") == 0) { cp->reply[0] = SMFIS_TEMPFAIL; } else if (strcmp(action, "reject") == 0) { cp->reply[0] = SMFIS_REJECT; } else if (strcmp(action, "accept") == 0) { cp->reply[0] = SMFIS_ACCEPT; } else if (strcmp(action, "discard") == 0) { cp->reply[0] = SMFIS_DISCARD; #ifdef SMFIS_SKIP } else if (strcmp(action, "skip") == 0) { cp->reply[0] = SMFIS_SKIP; #endif } else if ((code = atoi(action)) >= 400 && code <= 599 && action[3] == ' ') { cp->reply[0] = SMFIR_REPLYCODE; reply_code = action; reply_dsn = action + 3; if (*reply_dsn != 0) { *reply_dsn++ = 0; reply_dsn += strspn(reply_dsn, " "); } if (*reply_dsn == 0) { reply_dsn = reply_message = 0; } else { reply_message = reply_dsn + strcspn(reply_dsn, " "); if (*reply_message != 0) { *reply_message++ = 0; reply_message += strspn(reply_message, " "); } if (*reply_message == 0) reply_message = 0; } } else { fprintf(stderr, "bad -a argument: %s\n", action); exit(1); } if (verbose) { printf("command %s action %d\n", cp->name, cp->reply[0]); if (reply_code) printf("reply code %s dsn %s message %s\n", reply_code, reply_dsn ? reply_dsn : "(null)", reply_message ? reply_message : "(null)"); } } #if SMFI_VERSION > 5 if (set_macro_state_arg) { for (cpp = macro_states; /* see below */ ; cpp++) { if (*cpp == 0) { fprintf(stderr, "bad -m argument: %s\n", set_macro_state_arg); exit(1); } if (strcmp(set_macro_state_arg, *cpp) == 0) break; } set_macro_state = cpp - macro_states; } if (nosend) { for (np = noproto_map; /* see below */ ; np++) { if (np->name == 0) { fprintf(stderr, "bad -n argument: %s\n", nosend); exit(1); } if (strcmp(nosend, np->name) == 0) break; } nosend_mask = np->send_mask; np->action[0] = 0; } if (noreply) { for (np = noproto_map; /* see below */ ; np++) { if (np->name == 0) { fprintf(stderr, "bad -N argument: %s\n", noreply); exit(1); } if (strcmp(noreply, np->name) == 0) break; } noreply_mask = np->reply_mask; *np->reply = SMFIS_NOREPLY; } #endif if (smfi_register(smfilter) == MI_FAILURE) { fprintf(stderr, "smfi_register failed\n"); exit(1); } return (smfi_main()); }
int main(int argc, char **argv) { const char *opts = "b:D:dg:hst:u:H"; #ifdef HAS_LONGOPT static const struct option lopt[] = { {"bind", 1, 0, 'b'}, {"dry", 0, 0, 'H'}, {"debug", 1, 0, 'D'}, {"daemonize", 0, 0, 'd'}, {"group", 1, 0, 'g'}, {"help", 0, 0, 'h'}, {"no-stamp", 0, 0, 's'}, {"timeout", 1, 0, 't'}, {"user", 1, 0, 'u'}, {NULL, 0, 0, 0} }; #endif int c; char *p; char *oconn; int setconn; size_t len; int ret; uint8_t daemon; char *usr; char *grp; char *pidf = "/var/run/milter/dnsbl-milter.pid"; config.pname = argv[0]; p = strrchr(config.pname, '/'); if (p != NULL) config.pname = p + 1; if (argc < 2) { usage(config.pname); exit(EX_USAGE); } setconn = 0; oconn = NULL; config.daemon = 0; daemon = 0; usr = grp = NULL; config.stamp = 1; while ((c = getopt_long(argc, argv, opts, lopt, NULL)) != -1) { switch (c) { case 'b': /* bind address/socket */ if (setconn != 0) { mlog(LOG_ERR, "Bind address/socket already provided, ignoring"); break; } if ((optarg == NULL) || (*optarg == '\0')) { mlog(LOG_ERR, "No bind address/socket provided"); usage(config.pname); exit(EX_USAGE); } if ((strncmp(optarg, "unix:", 5) == 0) || (strncmp(optarg, "local:", 6) == 0) || (strncmp(optarg, "inet:", 5) == 0) || (strncmp(optarg, "inet6:", 6) == 0)) { oconn = optarg; setconn = 1; break; } /* "unix:" + optarg + '\0' */ len = 5 + strlen(optarg) + 1; oconn = malloc(len); if (oconn == NULL) { mlog(LOG_ERR, "Memory allocation failed"); exit(EX_UNAVAILABLE); } snprintf(oconn, len, "unix:%s", optarg); setconn = 2; break; case 'H': config.drymode = 1; // Adds a header instead of rejecting break; case 'D': if ((optarg == NULL) || (*optarg == '\0')) { mlog(LOG_ERR, "No debugging level provided"); usage(config.pname); exit(EX_USAGE); } smfi_setdbg(atoi(optarg)); break; case 'd': daemon = 1; break; case 'g': if ((optarg == NULL) || (*optarg == '\0')) { mlog(LOG_ERR, "No group provided"); usage(config.pname); exit(EX_USAGE); } grp = optarg; break; case 's': config.stamp = 0; break; case 't': if ((optarg == NULL) || (*optarg == '\0')) { mlog(LOG_ERR, "No timeout provided"); usage(config.pname); exit(EX_USAGE); } smfi_settimeout(atoi(optarg)); break; case 'u': if ((optarg == NULL) || (*optarg == '\0')) { mlog(LOG_ERR, "No user provided"); usage(config.pname); exit(EX_USAGE); } usr = optarg; break; case 'h': /* help */ default: usage(config.pname); exit(EX_USAGE); } } if (setconn == 0) { mlog(LOG_ERR, "%s: Missing required bind address/socket\n", config.pname); usage(config.pname); exit(EX_USAGE); } umask(0137); if ((oconn == NULL) || (smfi_setconn(oconn) == MI_FAILURE)) { mlog(LOG_ERR, "smfi_setconn() failed"); exit(EX_UNAVAILABLE); } if (smfi_register(smfilter) == MI_FAILURE) { mlog(LOG_ERR, "smfi_register() failed"); exit(EX_UNAVAILABLE); } /* List of blacklists to use */ list_add(&blacklist, "bl.spamcop.net", "Listed on SpamCop. See http://spamcop.net/w3m?action=checkblock&ip="); list_add(&blacklist, "b.barracudacentral.org", "Listed on Barracuda Reputation Block List (BRBL). See http://www.barracudacentral.org/lookups?ip_address="); list_add(&blacklist, "zen.spamhaus.org", "Listed on The Spamhaus Project. See http://www.spamhaus.org/query/bl?ip="); list_add(&blacklist, "psbl.surriel.com", "Listed on The Passive Spam Block List. See http://psbl.surriel.com/listing?ip="); /* List of whitelists to use */ list_add(&whitelist, "list.dnswl.org", "http://www.dnswl.org"); if ((usr != NULL) || (grp != NULL)) if (drop_privs(usr, grp) != 0) exit(EX_TEMPFAIL); if (daemon != 0) daemonize(); /* write pid file */ pidf_create(pidf); mlog(LOG_INFO, "Starting Sendmail %s filter '%s'", smfilter.xxfi_name, config.pname); ret = smfi_main(); /* remove pid file */ pidf_destroy(pidf); if (ret == MI_SUCCESS) { mlog(LOG_INFO, "Stopping Sendmail %s filter '%s'", smfilter.xxfi_name, config.pname); } else { mlog(LOG_ERR, "Abnormal termination of Sendmail %s filter '%s': %d", smfilter.xxfi_name, config.pname, ret); } list_free(&blacklist); list_free(&whitelist); if (setconn == 2) { free(oconn); oconn = NULL; } if (daemon != 0) closelog(); return ret; }