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;
}
예제 #2
0
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());
}
예제 #3
0
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;
}