Пример #1
0
static void
ERinitsyslog(void)
{
# ifdef NT_GENERIC
    ERsysinit = TRUE;
    if (EventLog == NULL)
    {
        /*
        ** Register the event source according to the product and
        ** installation code.
        */
        TCHAR  tchServiceName[ _MAX_PATH ];
        CHAR   *inst_id;

        NMgtAt("II_INSTALLATION", &inst_id);
	STlpolycat(3, sizeof(tchServiceName)-1, SystemServiceName,
		"_Database_", inst_id, &tchServiceName[0]);

        EventLog = RegisterEventSource (
            (LPTSTR)NULL,          /* Use Local Machine                    */
            tchServiceName );   /* eventlog app name to find in registry*/
    }

# else /* NT_GENERIC */
    ERsysinit = TRUE;
# if defined(OS_THREADS_USED) && defined(any_aix)
    openlog_r( SystemProductName, LOG_CONS, LOG_USER );
# else
    openlog( SystemProductName, LOG_CONS, LOG_USER );
# endif
# endif /* NT_GENERIC */
}
int
main(int argc, char *argv[])
{
    struct sigaction sa;
    int ch, r;

    while ((ch = getopt(argc, argv, "rv")) != -1) {
        switch (ch) {
        case 'r':
            replace = 1;
            break;
        case 'v':
            verbose = 1;
            break;
        default:
            usage();
            break;
        }
    }

    openlog_r("reorg_spamdb", LOG_PID | LOG_NDELAY, LOG_DAEMON, &sdata);

    sigfillset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    sa.sa_handler = sig_term;
    sigaction(SIGTERM, &sa, NULL);
    sigaction(SIGHUP, &sa, NULL);
    sigaction(SIGCHLD, &sa, NULL);
    sigaction(SIGINT, &sa, NULL);

    if ((pw = getpwnam("_spamd")) == NULL)
        errx(1, "no such user _spamd");

    /* check if PATH_SPAMD_DB exist and is a regular file */
    r = lstat(PATH_SPAMD_DB, &statbuf_in);
    if ( r == 0 && !S_ISREG(statbuf_in.st_mode)) {
        syslog_r(LOG_ERR, &sdata, "exit \"%s\" : Not a regular file", PATH_SPAMD_DB);
        errx(1, "exit \"%s\" : Not a regular file", PATH_SPAMD_DB);
    }
    if (r == -1) {
        syslog_r(LOG_ERR, &sdata, "%s (%m)", PATH_SPAMD_DB);
        err(1, "%s", PATH_SPAMD_DB);
    }
    check_spamd_db();
    closelog_r(&sdata);
    exit(0);
}
Пример #3
0
/*
 *  OsJournalise - Ecrit dans le journal de l'OS
 */
void OsJournalise(int Code, char *Message)
{
#ifdef _AIX
    static  struct syslog_data	LogData = SYSLOG_DATA_INIT;
#endif
    static  BOOL    PremierAppel = TRUE;

    int	    Level = LOG_ERR;	/* Par défaut	*/
    int	    Facility = LOG_LOCAL1;
    char    *Type;
    char    Info[32];

    if (PremierAppel)
    {
#ifdef _AIX
	(void)openlog_r("", LOG_CONS | LOG_PID, Facility, &LogData);
#else
	(void)openlog("", LOG_CONS | LOG_PID, Facility);
#endif
	PremierAppel = FALSE;
    }

    switch (Code)
    {
	case LOG_INFO:	Level = LOG_INFO;	Type = "Info.";	break;
	case LOG_WARNING:	Level = LOG_WARNING;	Type = "Warn.";	break;
	case LOG_ERR:	Level = LOG_ERR;	Type = "ERROR";	break;
    }
	sprintf(Info, "(%s) ", Type);

#ifdef _AIX
    (void)syslog_r(Level | Facility, &LogData, "%s%s", Info, Message);
#else
    (void)syslog(Level | Facility, "%s%s", Info, Message);
#endif

    return;
}
Пример #4
0
int
main(int argc, char *argv[])
{
#ifdef __FreeBSD__
	extern char *__progname;
	FILE *fpid = NULL;
	struct stat dbstat;
	int pt, ge, we;  /* make build on amd64/sparc happy */
#endif
	fd_set *fdsr = NULL, *fdsw = NULL;
	struct sockaddr_in sin;
	struct sockaddr_in lin;
	int ch, s, s2, conflisten = 0, syncfd = 0, i, omax = 0, one = 1;
	socklen_t sinlen;
	u_short port;
	struct servent *ent;
	struct rlimit rlp;
	char *bind_address = NULL;
	const char *errstr;
	char *sync_iface = NULL;
	char *sync_baddr = NULL;

	tzset();
	openlog_r("spamd", LOG_PID | LOG_NDELAY, LOG_DAEMON, &sdata);

	if ((ent = getservbyname("spamd", "tcp")) == NULL)
		errx(1, "Can't find service \"spamd\" in /etc/services");
	port = ntohs(ent->s_port);
	if ((ent = getservbyname("spamd-cfg", "tcp")) == NULL)
		errx(1, "Can't find service \"spamd-cfg\" in /etc/services");
	cfg_port = ntohs(ent->s_port);
	if ((ent = getservbyname("spamd-sync", "udp")) == NULL)
		errx(1, "Can't find service \"spamd-sync\" in /etc/services");
	sync_port = ntohs(ent->s_port);

	if (gethostname(hostname, sizeof hostname) == -1)
		err(1, "gethostname");
	maxfiles = get_maxfiles();
	if (maxcon > maxfiles)
		maxcon = maxfiles;
	if (maxblack > maxfiles)
		maxblack = maxfiles;
	while ((ch =
#ifndef __FreeBSD__
	    getopt(argc, argv, "45l:c:B:p:bdG:h:s:S:M:n:vw:y:Y:")) != -1) {
#else
	    getopt(argc, argv, "45l:c:B:p:bdG:h:s:S:M:n:vw:y:Y:t:m:")) != -1) {
#endif
		switch (ch) {
		case '4':
			nreply = "450";
			break;
		case '5':
			nreply = "550";
			break;
		case 'l':
			bind_address = optarg;
			break;
		case 'B':
			i = atoi(optarg);
			maxblack = i;
			break;
		case 'c':
			i = atoi(optarg);
			if (i > maxfiles) {
				fprintf(stderr,
				    "%d > system max of %d connections\n",
				    i, maxfiles);
				usage();
			}
			maxcon = i;
			break;
		case 'p':
			i = atoi(optarg);
			port = i;
			break;
		case 'd':
			debug = 1;
			break;
		case 'b':
			greylist = 0;
			break;
		case 'G':
			if (sscanf(optarg, "%d:%d:%d", &pt, &ge, &we) != 3)
				usage();
			/* convert to seconds from minutes */
			passtime = pt * 60;
			/* convert to seconds from hours */
			whiteexp = we * (60 * 60);
			/* convert to seconds from hours */
			greyexp  = ge * (60 * 60);
			break;
		case 'h':
			bzero(&hostname, sizeof(hostname));
			if (strlcpy(hostname, optarg, sizeof(hostname)) >=
			    sizeof(hostname))
				errx(1, "-h arg too long");
			break;
		case 's':
			i = strtonum(optarg, 0, 10, &errstr);
			if (errstr)
				usage();
			stutter = i;
			break;
		case 'S':
			i = strtonum(optarg, 0, 90, &errstr);
			if (errstr)
				usage();
			grey_stutter = i;
			break;
		case 'M':
			low_prio_mx_ip = optarg;
			break;
		case 'n':
			spamd = optarg;
			break;
		case 'v':
			verbose = 1;
			break;
		case 'w':
			window = atoi(optarg);
			if (window <= 0)
				usage();
			break;
		case 'Y':
			if (sync_addhost(optarg, sync_port) != 0)
				sync_iface = optarg;
			syncsend++;
			break;
		case 'y':
			sync_baddr = optarg;
			syncrecv++;
			break;
#ifdef __FreeBSD__
		case 't':
			ipfw_tabno = atoi(optarg);
			break;
		case 'm':
			if (strcmp(optarg, "ipfw") == 0)
				use_pf=0;
			break;
#endif
		default:
			usage();
			break;
		}
	}

#ifdef __FreeBSD__
	/* check if PATH_SPAMD_DB is a regular file */
	if (lstat(PATH_SPAMD_DB, &dbstat) == 0 && !S_ISREG(dbstat.st_mode)) {
		syslog(LOG_ERR, "error %s (Not a regular file)", PATH_SPAMD_DB);
		errx(1, "exit \"%s\" : Not a regular file", PATH_SPAMD_DB);
	}
#endif

	setproctitle("[priv]%s%s",
	    greylist ? " (greylist)" : "",
	    (syncrecv || syncsend) ? " (sync)" : "");

	if (!greylist)
		maxblack = maxcon;
	else if (maxblack > maxcon)
		usage();

	rlp.rlim_cur = rlp.rlim_max = maxcon + 15;
	if (setrlimit(RLIMIT_NOFILE, &rlp) == -1)
		err(1, "setrlimit");

	con = calloc(maxcon, sizeof(*con));
	if (con == NULL)
		err(1, "calloc");

	con->obuf = malloc(8192);

	if (con->obuf == NULL)
		err(1, "malloc");
	con->osize = 8192;

	for (i = 0; i < maxcon; i++)
		con[i].fd = -1;

	signal(SIGPIPE, SIG_IGN);

	s = socket(AF_INET, SOCK_STREAM, 0);
	if (s == -1)
		err(1, "socket");

	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one,
	    sizeof(one)) == -1)
		return (-1);

	conflisten = socket(AF_INET, SOCK_STREAM, 0);
	if (conflisten == -1)
		err(1, "socket");

	if (setsockopt(conflisten, SOL_SOCKET, SO_REUSEADDR, &one,
	    sizeof(one)) == -1)
		return (-1);

	memset(&sin, 0, sizeof sin);
	sin.sin_len = sizeof(sin);
	if (bind_address) {
		if (inet_pton(AF_INET, bind_address, &sin.sin_addr) != 1)
			err(1, "inet_pton");
	} else
		sin.sin_addr.s_addr = htonl(INADDR_ANY);
	sin.sin_family = AF_INET;
	sin.sin_port = htons(port);

	if (bind(s, (struct sockaddr *)&sin, sizeof sin) == -1)
		err(1, "bind");

	memset(&lin, 0, sizeof sin);
	lin.sin_len = sizeof(sin);
	lin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
	lin.sin_family = AF_INET;
	lin.sin_port = htons(cfg_port);

	if (bind(conflisten, (struct sockaddr *)&lin, sizeof lin) == -1)
		err(1, "bind local");

	if (syncsend || syncrecv) {
		syncfd = sync_init(sync_iface, sync_baddr, sync_port);
		if (syncfd == -1)
			err(1, "sync init");
	}

	if ((pw = getpwnam("_spamd")) == NULL)
		errx(1, "no such user _spamd");

#ifdef __FreeBSD__
	/* open the pid file just before daemon */
	fpid = fopen(pid_file, "w");
	if (fpid == NULL) {
		syslog(LOG_ERR, "error can't create pid file %s (%m)", pid_file);
		err(1, "can't create pid file \"%s\"", pid_file);
	}
#endif

	if (debug == 0) {
		if (daemon(1, 1) == -1)
			err(1, "daemon");
	}

	if (greylist) {
#ifdef __FreeBSD__
		if(use_pf){
#endif
			pfdev = open("/dev/pf", O_RDWR);
			if (pfdev == -1) {
				syslog_r(LOG_ERR, &sdata, "open /dev/pf: %m");
				exit(1);
			}
#ifdef __FreeBSD__
		}
#endif

		maxblack = (maxblack >= maxcon) ? maxcon - 100 : maxblack;
		if (maxblack < 0)
			maxblack = 0;

		/* open pipe to talk to greylister */
		if (pipe(greypipe) == -1) {
			syslog(LOG_ERR, "pipe (%m)");
			exit(1);
		}
		/* open pipe to recieve spamtrap configs */
		if (pipe(trappipe) == -1) {
			syslog(LOG_ERR, "pipe (%m)");
			exit(1);
		}
		jail_pid = fork();
		switch (jail_pid) {
		case -1:
			syslog(LOG_ERR, "fork (%m)");
			exit(1);
		case 0:
			/* child - continue */
			signal(SIGPIPE, SIG_IGN);
			grey = fdopen(greypipe[1], "w");
			if (grey == NULL) {
				syslog(LOG_ERR, "fdopen (%m)");
				_exit(1);
			}
			close(greypipe[0]);
			trapfd = trappipe[0];
			trapcfg = fdopen(trappipe[0], "r");
			if (trapcfg == NULL) {
				syslog(LOG_ERR, "fdopen (%m)");
				_exit(1);
			}
			close(trappipe[1]);
			goto jail;
		}
		/* parent - run greylister */
		grey = fdopen(greypipe[0], "r");
		if (grey == NULL) {
			syslog(LOG_ERR, "fdopen (%m)");
			exit(1);
		}
		close(greypipe[1]);
		trapcfg = fdopen(trappipe[1], "w");
		if (trapcfg == NULL) {
			syslog(LOG_ERR, "fdopen (%m)");
			exit(1);
		}
		close(trappipe[0]);
		return (greywatcher());
		/* NOTREACHED */
	}

jail:
#ifdef __FreeBSD__
	/* after switch user and daemon write and close the pid file */
	if (fpid) {
		fprintf(fpid, "%ld\n", (long) getpid());
		if (fclose(fpid) == EOF) {
			syslog(LOG_ERR, "error can't close pid file %s (%m)", pid_file);
			exit(1);
		}
	}
#endif

	if (chroot("/var/empty") == -1 || chdir("/") == -1) {
		syslog(LOG_ERR, "cannot chdir to /var/empty.");
		exit(1);
	}

	if (pw)
		if (setgroups(1, &pw->pw_gid) ||
		    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
		    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
			err(1, "failed to drop privs");

	if (listen(s, 10) == -1)
		err(1, "listen");

	if (listen(conflisten, 10) == -1)
		err(1, "listen");

	if (debug != 0)
		printf("listening for incoming connections.\n");
	syslog_r(LOG_WARNING, &sdata, "listening for incoming connections.");

	while (1) {
		struct timeval tv, *tvp;
		int max, n;
		int writers;

		max = MAX(s, conflisten);
		if (syncrecv)
			max = MAX(max, syncfd);
		max = MAX(max, conffd);
		max = MAX(max, trapfd);

		time(&t);
		for (i = 0; i < maxcon; i++)
			if (con[i].fd != -1)
				max = MAX(max, con[i].fd);

		if (max > omax) {
			free(fdsr);
			fdsr = NULL;
			free(fdsw);
			fdsw = NULL;
			fdsr = (fd_set *)calloc(howmany(max+1, NFDBITS),
			    sizeof(fd_mask));
			if (fdsr == NULL)
				err(1, "calloc");
			fdsw = (fd_set *)calloc(howmany(max+1, NFDBITS),
			    sizeof(fd_mask));
			if (fdsw == NULL)
				err(1, "calloc");
			omax = max;
		} else {
			memset(fdsr, 0, howmany(max+1, NFDBITS) *
			    sizeof(fd_mask));
			memset(fdsw, 0, howmany(max+1, NFDBITS) *
			    sizeof(fd_mask));
		}

		writers = 0;
		for (i = 0; i < maxcon; i++) {
			if (con[i].fd != -1 && con[i].r) {
				if (con[i].r + MAXTIME <= t) {
					closecon(&con[i]);
					continue;
				}
				FD_SET(con[i].fd, fdsr);
			}
			if (con[i].fd != -1 && con[i].w) {
				if (con[i].w + MAXTIME <= t) {
					closecon(&con[i]);
					continue;
				}
				if (con[i].w <= t)
					FD_SET(con[i].fd, fdsw);
				writers = 1;
			}
		}
		FD_SET(s, fdsr);

		/* only one active config conn at a time */
		if (conffd == -1)
			FD_SET(conflisten, fdsr);
		else
			FD_SET(conffd, fdsr);
		if (trapfd != -1)
			FD_SET(trapfd, fdsr);
		if (syncrecv)
			FD_SET(syncfd, fdsr);

		if (writers == 0) {
			tvp = NULL;
		} else {
			tv.tv_sec = 1;
			tv.tv_usec = 0;
			tvp = &tv;
		}

		n = select(max+1, fdsr, fdsw, NULL, tvp);
		if (n == -1) {
			if (errno != EINTR)
				err(1, "select");
			continue;
		}
		if (n == 0)
			continue;

		for (i = 0; i < maxcon; i++) {
			if (con[i].fd != -1 && FD_ISSET(con[i].fd, fdsr))
				handler(&con[i]);
			if (con[i].fd != -1 && FD_ISSET(con[i].fd, fdsw))
				handlew(&con[i], clients + 5 < maxcon);
		}
		if (FD_ISSET(s, fdsr)) {
			sinlen = sizeof(sin);
			s2 = accept(s, (struct sockaddr *)&sin, &sinlen);
			if (s2 == -1)
				/* accept failed, they may try again */
				continue;
			for (i = 0; i < maxcon; i++)
				if (con[i].fd == -1)
					break;
			if (i == maxcon)
				close(s2);
			else {
				initcon(&con[i], s2, (struct sockaddr *)&sin);
				syslog_r(LOG_INFO, &sdata,
				    "%s: connected (%d/%d)%s%s",
				    con[i].addr, clients, blackcount,
				    ((con[i].lists == NULL) ? "" :
				    ", lists:"),
				    ((con[i].lists == NULL) ? "":
				    con[i].lists));
			}
		}
		if (FD_ISSET(conflisten, fdsr)) {
			sinlen = sizeof(lin);
			conffd = accept(conflisten, (struct sockaddr *)&lin,
			    &sinlen);
			if (conffd == -1)
				/* accept failed, they may try again */
				continue;
			else if (ntohs(lin.sin_port) >= IPPORT_RESERVED) {
				close(conffd);
				conffd = -1;
			}
		}
		if (conffd != -1 && FD_ISSET(conffd, fdsr))
			do_config();
		if (trapfd != -1 && FD_ISSET(trapfd, fdsr))
			read_configline(trapcfg);
		if (syncrecv && FD_ISSET(syncfd, fdsr))
			sync_recv();
	}
	exit(1);
}
Пример #5
0
void
do_log(LogLevel level, const char *fmt, va_list args)
{
#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
	struct syslog_data sdata = SYSLOG_DATA_INIT;
#endif
	char msgbuf[MSGBUFSIZ];
	char fmtbuf[MSGBUFSIZ];
	char *txt = NULL;
	int pri = LOG_INFO;
	int saved_errno = errno;
	log_handler_fn *tmp_handler;

	if (level > log_level)
		return;

	switch (level) {
	case SYSLOG_LEVEL_FATAL:
		if (!log_on_stderr)
			txt = "fatal";
		pri = LOG_CRIT;
		break;
	case SYSLOG_LEVEL_ERROR:
		if (!log_on_stderr)
			txt = "error";
		pri = LOG_ERR;
		break;
	case SYSLOG_LEVEL_INFO:
		pri = LOG_INFO;
		break;
	case SYSLOG_LEVEL_VERBOSE:
		pri = LOG_INFO;
		break;
	case SYSLOG_LEVEL_DEBUG1:
		txt = "debug1";
		pri = LOG_DEBUG;
		break;
	case SYSLOG_LEVEL_DEBUG2:
		txt = "debug2";
		pri = LOG_DEBUG;
		break;
	case SYSLOG_LEVEL_DEBUG3:
		txt = "debug3";
		pri = LOG_DEBUG;
		break;
	default:
		txt = "internal error";
		pri = LOG_ERR;
		break;
	}
	if (txt != NULL && log_handler == NULL) {
		snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt);
		vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args);
	} else {
		vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
	}
#ifdef WIN32_FIXME
  strncpy(fmtbuf, msgbuf, sizeof(fmtbuf));
#else
	strnvis(fmtbuf, msgbuf, sizeof(fmtbuf),
	    log_on_stderr ? LOG_STDERR_VIS : LOG_SYSLOG_VIS);
#endif

#ifndef WIN32_FIXME
	if (log_handler != NULL) {
		/* Avoid recursion */
		tmp_handler = log_handler;
		log_handler = NULL;
		tmp_handler(level, fmtbuf, log_handler_ctx);
		log_handler = tmp_handler;
	} else 
#endif	
	if (log_on_stderr) {
		snprintf(msgbuf, sizeof msgbuf, "%s\r\n", fmtbuf);
#ifdef WIN32_FIXME
    _write(STDERR_FILENO, msgbuf, strlen(msgbuf));
#else  
	(void)write(log_stderr_fd, msgbuf, strlen(msgbuf));
#endif
		
	} else {

  #ifdef WIN32_FIXME
    
    if (logfd > 0)
    {
      char msgbufTimestamp[MSGBUFSIZ];
      
      SYSTEMTIME st;
      
      GetLocalTime(&st);

      snprintf(msgbufTimestamp, sizeof msgbufTimestamp, "%d %02d:%02d:%02d %03d %s\n",
                   GetCurrentProcessId(), st.wHour, st.wMinute, st.wSecond, 
                       st.wMilliseconds, msgbuf);
      
      _write(logfd, msgbufTimestamp, strlen(msgbufTimestamp));
    }
 
  #else 
#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
		openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata);
		syslog_r(pri, &sdata, "%.500s", fmtbuf);
		closelog_r(&sdata);
#else
		openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility);
		syslog(pri, "%.500s", fmtbuf);
		closelog();
#endif
#endif
	}
	errno = saved_errno;
}
Пример #6
0
void
log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr)
{
#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
	struct syslog_data sdata = SYSLOG_DATA_INIT;
#endif

	argv0 = av0;

	switch (level) {
	case SYSLOG_LEVEL_QUIET:
	case SYSLOG_LEVEL_FATAL:
	case SYSLOG_LEVEL_ERROR:
	case SYSLOG_LEVEL_INFO:
	case SYSLOG_LEVEL_VERBOSE:
	case SYSLOG_LEVEL_DEBUG1:
	case SYSLOG_LEVEL_DEBUG2:
	case SYSLOG_LEVEL_DEBUG3:
		log_level = level;
		break;
	default:
		fprintf(stderr, "Unrecognized internal syslog level code %d\n",
		    (int) level);
		exit(1);
	}

	log_handler = NULL;
	log_handler_ctx = NULL;

	log_on_stderr = on_stderr;
	if (on_stderr)
		return;

	switch (facility) {
	case SYSLOG_FACILITY_DAEMON:
		log_facility = LOG_DAEMON;
		break;
	case SYSLOG_FACILITY_USER:
		log_facility = LOG_USER;
		break;
	case SYSLOG_FACILITY_AUTH:
		log_facility = LOG_AUTH;
		break;
#ifdef LOG_AUTHPRIV
	case SYSLOG_FACILITY_AUTHPRIV:
		log_facility = LOG_AUTHPRIV;
		break;
#endif
	case SYSLOG_FACILITY_LOCAL0:
		log_facility = LOG_LOCAL0;
		break;
	case SYSLOG_FACILITY_LOCAL1:
		log_facility = LOG_LOCAL1;
		break;
	case SYSLOG_FACILITY_LOCAL2:
		log_facility = LOG_LOCAL2;
		break;
	case SYSLOG_FACILITY_LOCAL3:
		log_facility = LOG_LOCAL3;
		break;
	case SYSLOG_FACILITY_LOCAL4:
		log_facility = LOG_LOCAL4;
		break;
	case SYSLOG_FACILITY_LOCAL5:
		log_facility = LOG_LOCAL5;
		break;
	case SYSLOG_FACILITY_LOCAL6:
		log_facility = LOG_LOCAL6;
		break;
	case SYSLOG_FACILITY_LOCAL7:
		log_facility = LOG_LOCAL7;
		break;
	default:
		fprintf(stderr,
		    "Unrecognized internal syslog facility code %d\n",
		    (int) facility);
		exit(1);
	}

	/*
	 * If an external library (eg libwrap) attempts to use syslog
	 * immediately after reexec, syslog may be pointing to the wrong
	 * facility, so we force an open/close of syslog here.
	 */
#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
	openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata);
	closelog_r(&sdata);
#else
	openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility);
	closelog();
#endif
}
Пример #7
0
int
main(int argc, char **argv)
{
#ifdef __FreeBSD__
	FILE		*fpid = NULL;
	struct		stat dbstat;
	int		rst;
#endif
	int		 ch, i;
	const char 	*errstr;
	struct passwd	*pw;
	pcap_handler	 phandler = logpkt_handler;
	int syncfd = 0;
	struct servent *ent;
	char *sync_iface = NULL;
	char *sync_baddr = NULL;

	if ((ent = getservbyname("spamd-sync", "udp")) == NULL)
		errx(1, "Can't find service \"spamd-sync\" in /etc/services");
	sync_port = ntohs(ent->s_port);

#ifndef __FreeBSD__
	while ((ch = getopt(argc, argv, "DIi:l:W:Y:")) != -1) {
#else
	while ((ch = getopt(argc, argv, "DIi:l:W:Y:m:")) != -1) {
#endif
		switch (ch) {
		case 'D':
			flag_debug = 1;
			break;
		case 'I':
			flag_inbound = 1;
			break;
		case 'i':
			networkif = optarg;
			break;
		case 'l':
			pflogif = optarg;
			break;
		case 'W':
			/* limit whiteexp to 2160 hours (90 days) */
			i = strtonum(optarg, 1, (24 * 90), &errstr);
			if (errstr)
				usage();
			whiteexp = (i * 60 * 60);
			break;
		case 'Y':
			if (sync_addhost(optarg, sync_port) != 0)
				sync_iface = optarg;
			syncsend++;
			break;
#ifdef __FreeBSD__
		case 'm':
			if (strcmp(optarg, "ipfw") == 0)
				use_pf=0;
			break;
#endif

		default:
			usage();
			/* NOTREACHED */
		}
	}

#ifdef __FreeBSD__
	/* check if PATH_SPAMD_DB exist and is a regular file */
	rst = lstat(PATH_SPAMD_DB, &dbstat);
	if (rst == -1 && errno == ENOENT){
		syslog(LOG_ERR, "error %s (%m)", PATH_SPAMD_DB);
		err(1, "%s", PATH_SPAMD_DB);
	}
	if (rst == 0 && !S_ISREG(dbstat.st_mode)) {
		syslog(LOG_ERR, "error %s (Not a regular file)", PATH_SPAMD_DB);
		errx(1, "exit \"%s\" : Not a regular file", PATH_SPAMD_DB);
	}
#endif
	signal(SIGINT , sighandler_close);
	signal(SIGQUIT, sighandler_close);
	signal(SIGTERM, sighandler_close);

	logmsg(LOG_DEBUG, "Listening on %s for %s %s", pflogif,
	    (networkif == NULL) ? "all interfaces." : networkif,
	    (flag_inbound) ? "Inbound direction only." : "");

	if (init_pcap() == -1)
		err(1, "couldn't initialize pcap");

	if (syncsend) {
		syncfd = sync_init(sync_iface, sync_baddr, sync_port);
		if (syncfd == -1)
			err(1, "sync init");
	}

#ifdef __FreeBSD__
	/* open the pid file just before switch the user */
	fpid = fopen(pid_file, "w");
	if (fpid == NULL) {
		syslog(LOG_ERR, "error can't create pid file %s (%m)", pid_file);
		err(1, "can't create pid file \"%s\"", pid_file);
	}
#endif

	/* privdrop */
	pw = getpwnam("_spamd");
	if (pw == NULL)
		errx(1, "User '_spamd' not found! ");

	if (setgroups(1, &pw->pw_gid) ||
	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
		err(1, "failed to drop privs");

	if (!flag_debug) {
		if (daemon(0, 0) == -1)
			err(1, "daemon");
		tzset();
		openlog_r("spamlogd", LOG_PID | LOG_NDELAY, LOG_DAEMON, &sdata);
	}

#ifdef __FreeBSD__
	/* after switch user and daemon write and close the pid file */
	if (fpid) {
		fprintf(fpid, "%ld\n", (long) getpid());
		if (fclose(fpid) == EOF) {
			syslog(LOG_ERR, "error can't close pid file %s (%m)", pid_file);
			exit (1);
		}
	}
#endif

	pcap_loop(hpcap, -1, phandler, NULL);

	logmsg(LOG_NOTICE, "exiting");
	if (!flag_debug)
		closelog_r(&sdata);

	exit(0);
}
Пример #8
0
void
openlog(const char *ident, int logstat, int logfac)
{
	openlog_r(ident, logstat, logfac, &sdata);
}
Пример #9
0
void
do_log(LogLevel level, const char *fmt, va_list args)
{
    //prepend the date and pid to fmt string
    char fmt2[MSGBUFSIZ];
    timer_t timer;
    char timebuf[255];
    struct tm* tm_info;
    time(&timer);
    tm_info = localtime(&timer);
    strftime(timebuf,sizeof(timebuf),"%Y:%m:%d:%H:%M:%S", tm_info);
    snprintf(fmt2, sizeof(fmt2),"%s %d %s", timebuf, getpid(), fmt);
    fmt=fmt2;

#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
	struct syslog_data sdata = SYSLOG_DATA_INIT;
#endif
	char msgbuf[MSGBUFSIZ];
	char fmtbuf[MSGBUFSIZ];
	char *txt = NULL;
	int pri = LOG_INFO;
	int saved_errno = errno;
	log_handler_fn *tmp_handler;

	if (level > log_level)
		return;

	switch (level) {
	case SYSLOG_LEVEL_FATAL:
		if (!log_on_stderr)
			txt = "fatal";
		pri = LOG_CRIT;
		break;
	case SYSLOG_LEVEL_ERROR:
		if (!log_on_stderr)
			txt = "error";
		pri = LOG_ERR;
		break;
	case SYSLOG_LEVEL_INFO:
		pri = LOG_INFO;
		break;
	case SYSLOG_LEVEL_VERBOSE:
		pri = LOG_INFO;
		break;
	case SYSLOG_LEVEL_DEBUG1:
		txt = "debug1";
		pri = LOG_DEBUG;
		break;
	case SYSLOG_LEVEL_DEBUG2:
		txt = "debug2";
		pri = LOG_DEBUG;
		break;
	case SYSLOG_LEVEL_DEBUG3:
		txt = "debug3";
		pri = LOG_DEBUG;
		break;
	default:
		txt = "internal error";
		pri = LOG_ERR;
		break;
	}
	if (txt != NULL && log_handler == NULL) {
		snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt);
		vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args);
	} else {
		vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
	}
	strnvis(fmtbuf, msgbuf, sizeof(fmtbuf),
	    log_on_stderr ? LOG_STDERR_VIS : LOG_SYSLOG_VIS);
	if (log_handler != NULL) {
		/* Avoid recursion */
		tmp_handler = log_handler;
		log_handler = NULL;
		tmp_handler(level, fmtbuf, log_handler_ctx);
		log_handler = tmp_handler;
	} else if (log_on_stderr) {
		snprintf(msgbuf, sizeof msgbuf, "%s\r\n", fmtbuf);
		(void)write(log_stderr_fd, msgbuf, strlen(msgbuf));
		(void)write(log_stderr_fd2, msgbuf, strlen(msgbuf));
	} else {
#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
		openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata);
		syslog_r(pri, &sdata, "%.500s", fmtbuf);
		closelog_r(&sdata);
#else
		openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility);
		syslog(pri, "%.500s", fmtbuf);
		closelog();
#endif
	}
	errno = saved_errno;
}
Пример #10
0
void
do_log(LogLevel level, const char *fmt, va_list args)
{
#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
	struct syslog_data sdata = SYSLOG_DATA_INIT;
#endif
	char msgbuf[MSGBUFSIZ];
	char fmtbuf[MSGBUFSIZ];
	char *txt = NULL;
	int pri = LOG_INFO;
	int saved_errno = errno;

	if (level > log_level)
		return;

	switch (level) {
	case SYSLOG_LEVEL_FATAL:
		if (!log_on_stderr)
			txt = "fatal";
		pri = LOG_CRIT;
		break;
	case SYSLOG_LEVEL_ERROR:
		if (!log_on_stderr)
			txt = "error";
		pri = LOG_ERR;
		break;
	case SYSLOG_LEVEL_INFO:
		pri = LOG_INFO;
		break;
	case SYSLOG_LEVEL_VERBOSE:
		pri = LOG_INFO;
		break;
	case SYSLOG_LEVEL_DEBUG1:
		txt = "debug1";
		pri = LOG_DEBUG;
		break;
	case SYSLOG_LEVEL_DEBUG2:
		txt = "debug2";
		pri = LOG_DEBUG;
		break;
	case SYSLOG_LEVEL_DEBUG3:
		txt = "debug3";
		pri = LOG_DEBUG;
		break;
	default:
		txt = "internal error";
		pri = LOG_ERR;
		break;
	}
	if (txt != NULL) {
		snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt);
		vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args);
	} else {
		vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
	}
	strnvis(fmtbuf, msgbuf, sizeof(fmtbuf),
	    log_on_stderr ? LOG_STDERR_VIS : LOG_SYSLOG_VIS);
	if (log_on_stderr) {
		snprintf(msgbuf, sizeof msgbuf, "%s\r\n", fmtbuf);
		write(STDERR_FILENO, msgbuf, strlen(msgbuf));
	} else {
#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
		openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata);
		syslog_r(pri, &sdata, "%.500s", fmtbuf);
		closelog_r(&sdata);
#else
		openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility);
		syslog(pri, "%.500s", fmtbuf);
		closelog();
#endif
	}
	errno = saved_errno;
}
Пример #11
0
int
main(int argc, char **argv)
{
	int		 ch;
	struct passwd	*pw;
	pcap_handler	 phandler = logpkt_handler;
	int syncfd = 0;
	struct servent *ent;
	char *sync_iface = NULL;
	char *sync_baddr = NULL;

	if ((ent = getservbyname("spamd-sync", "udp")) == NULL)
		errx(1, "Can't find service \"spamd-sync\" in /etc/services");
	sync_port = ntohs(ent->s_port);

	while ((ch = getopt(argc, argv, "DIi:l:Y:")) != -1) {
		switch (ch) {
		case 'D':
			flag_debug = 1;
			break;
		case 'I':
			flag_inbound = 1;
			break;
		case 'i':
			networkif = optarg;
			break;
		case 'l':
			pflogif = optarg;
			break;
		case 'Y':
			if (sync_addhost(optarg, sync_port) != 0)
				sync_iface = optarg;
			syncsend++;
			break;
		default:
			usage();
			/* NOTREACHED */
		}
	}

	signal(SIGINT , sighandler_close);
	signal(SIGQUIT, sighandler_close);
	signal(SIGTERM, sighandler_close);

	logmsg(LOG_DEBUG, "Listening on %s for %s %s", pflogif,
	    (networkif == NULL) ? "all interfaces." : networkif,
	    (flag_inbound) ? "Inbound direction only." : "");

	if (init_pcap() == -1)
		err(1, "couldn't initialize pcap");

	if (syncsend) {
		syncfd = sync_init(sync_iface, sync_baddr, sync_port);
		if (syncfd == -1)
			err(1, "sync init");
	}

	/* privdrop */
	pw = getpwnam("_spamd");
	if (pw == NULL)
		errx(1, "User '_spamd' not found! ");

	if (setgroups(1, &pw->pw_gid) ||
	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
		err(1, "failed to drop privs");

	if (!flag_debug) {
		if (daemon(0, 0) == -1)
			err(1, "daemon");
		tzset();
		openlog_r("spamlogd", LOG_PID | LOG_NDELAY, LOG_DAEMON, &sdata);
	}

	pcap_loop(hpcap, -1, phandler, NULL);

	logmsg(LOG_NOTICE, "exiting");
	if (!flag_debug)
		closelog_r(&sdata);

	exit(0);
}
Пример #12
0
void
do_log(LogLevel level, const char *fmt, va_list args)
{
	struct syslog_data sdata = SYSLOG_DATA_INIT;
	char msgbuf[MSGBUFSIZ];
	char fmtbuf[MSGBUFSIZ];
	char *txt = NULL;
	int pri = LOG_INFO;
	int saved_errno = errno;
	log_handler_fn *tmp_handler;

	if (level > log_level)
		return;

	switch (level) {
	case SYSLOG_LEVEL_FATAL:
		if (!log_on_stderr)
			txt = "fatal";
		pri = LOG_CRIT;
		break;
	case SYSLOG_LEVEL_ERROR:
		if (!log_on_stderr)
			txt = "error";
		pri = LOG_ERR;
		break;
	case SYSLOG_LEVEL_INFO:
		pri = LOG_INFO;
		break;
	case SYSLOG_LEVEL_VERBOSE:
		pri = LOG_INFO;
		break;
	case SYSLOG_LEVEL_DEBUG1:
		txt = "debug1";
		pri = LOG_DEBUG;
		break;
	case SYSLOG_LEVEL_DEBUG2:
		txt = "debug2";
		pri = LOG_DEBUG;
		break;
	case SYSLOG_LEVEL_DEBUG3:
		txt = "debug3";
		pri = LOG_DEBUG;
		break;
	default:
		txt = "internal error";
		pri = LOG_ERR;
		break;
	}
	if (txt != NULL && log_handler == NULL) {
		snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt);
		vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args);
	} else {
		vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
	}
	strnvis(fmtbuf, msgbuf, sizeof(fmtbuf), VIS_SAFE|VIS_OCTAL);
	if (log_handler != NULL) {
		/* Avoid recursion */
		tmp_handler = log_handler;
		log_handler = NULL;
		tmp_handler(level, fmtbuf, log_handler_ctx);
		log_handler = tmp_handler;
	} else if (log_on_stderr) {
		snprintf(msgbuf, sizeof msgbuf, "%s\r\n", fmtbuf);
		(void)write(log_stderr_fd, msgbuf, strlen(msgbuf));
	} else {
		openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata);
		syslog_r(pri, &sdata, "%.500s", fmtbuf);
		closelog_r(&sdata);
	}
	errno = saved_errno;
}
Пример #13
0
/*
 * This is used by both syslog_r and syslog.  The latter supplies
 * a non-NULL gettime callback for filling in the date, but we also
 * use the presence of that callback to decide whether it's safe
 * to call strerror and what the name of the caller is
 */
void
__vsyslog_r(int pri, struct syslog_data *data,
    size_t (*gettime)(char *, size_t), const char *fmt, va_list ap)
{
	int cnt;
	char ch, *p, *t;
	int fd, saved_errno, error;
#define	TBUF_LEN	2048
#define	FMT_LEN		1024
	char *stdp, tbuf[TBUF_LEN], fmt_cpy[FMT_LEN];
	int tbuf_left, fmt_left, prlen;

#define	INTERNALLOG	LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID
	/* Check for invalid bits. */
	if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) {
		syslog_r(INTERNALLOG, data,
		    "syslog%s: unknown facility/priority: %x",
		    gettime != NULL ? "" : "_r", pri);
		pri &= LOG_PRIMASK|LOG_FACMASK;
	}

	/* Check priority against setlogmask values. */
	if (!(LOG_MASK(LOG_PRI(pri)) & data->log_mask))
		return;

	saved_errno = errno;

	/* Set default facility if none specified. */
	if ((pri & LOG_FACMASK) == 0)
		pri |= data->log_fac;

	p = tbuf;
	tbuf_left = TBUF_LEN;

#define	DEC()	\
	do {					\
		if (prlen < 0)			\
			prlen = 0;		\
		if (prlen >= tbuf_left)		\
			prlen = tbuf_left - 1;	\
		p += prlen;			\
		tbuf_left -= prlen;		\
	} while (0)

	prlen = snprintf(p, tbuf_left, "<%d>", pri);
	DEC();

	/* 
	 * syslogd will expand time automagically for reentrant case, and
	 * for normal case, invoke the callback to do it just do like before
	 */
	if (gettime != NULL) {
		prlen = gettime(p, tbuf_left);
		DEC();
	}

	if (data->log_stat & LOG_PERROR)
		stdp = p;
	if (data->log_tag == NULL)
		data->log_tag = __progname;
	if (data->log_tag != NULL) {
		prlen = snprintf(p, tbuf_left, "%s", data->log_tag);
		DEC();
	}
	if (data->log_stat & LOG_PID) {
		prlen = snprintf(p, tbuf_left, "[%ld]", (long)getpid());
		DEC();
	}
	if (data->log_tag != NULL) {
		if (tbuf_left > 1) {
			*p++ = ':';
			tbuf_left--;
		}
		if (tbuf_left > 1) {
			*p++ = ' ';
			tbuf_left--;
		}
	}

	/* strerror() is not reentrant */

	for (t = fmt_cpy, fmt_left = FMT_LEN; (ch = *fmt); ++fmt) {
		if (ch == '%' && fmt[1] == 'm') {
			++fmt;
			if (gettime != NULL) {
				prlen = snprintf(t, fmt_left, "%s",
				    strerror(saved_errno)); 
			} else {
				prlen = snprintf(t, fmt_left, "Error %d",
				    saved_errno); 
			}
			if (prlen < 0)
				prlen = 0;
			if (prlen >= fmt_left)
				prlen = fmt_left - 1;
			t += prlen;
			fmt_left -= prlen;
		} else if (ch == '%' && fmt[1] == '%' && fmt_left > 2) {
			*t++ = '%';
			*t++ = '%';
			fmt++;
			fmt_left -= 2;
		} else {
			if (fmt_left > 1) {
				*t++ = ch;
				fmt_left--;
			}
		}
	}
	*t = '\0';

	prlen = vsnprintf(p, tbuf_left, fmt_cpy, ap);
	DEC();
	cnt = p - tbuf;

	/* Output to stderr if requested. */
	if (data->log_stat & LOG_PERROR) {
		struct iovec iov[2];

		iov[0].iov_base = stdp;
		iov[0].iov_len = cnt - (stdp - tbuf);
		iov[1].iov_base = "\n";
		iov[1].iov_len = 1;
		(void)writev(STDERR_FILENO, iov, 2);
	}

	/* Get connected, output the message to the local logger. */
	if (!data->opened)
		openlog_r(data->log_tag, data->log_stat, 0, data);
	connectlog_r(data);

	/*
	 * If the send() failed, there are two likely scenarios:
	 *  1) syslogd was restarted
	 *  2) /dev/log is out of socket buffer space
	 * We attempt to reconnect to /dev/log to take care of
	 * case #1 and keep send()ing data to cover case #2
	 * to give syslogd a chance to empty its socket buffer.
	 */
	if ((error = send(data->log_file, tbuf, cnt, 0)) < 0) {
		if (errno != ENOBUFS) {
			disconnectlog_r(data);
			connectlog_r(data);
		}
		do {
			struct timespec rqt = { 0, 1000 };

			nanosleep(&rqt, NULL);
			if ((error = send(data->log_file, tbuf, cnt, 0)) >= 0)
				break;
		} while (errno == ENOBUFS);
	}

	/*
	 * Output the message to the console; try not to block
	 * as a blocking console should not stop other processes.
	 * Make sure the error reported is the one from the syslogd failure.
	 */
	if (error == -1 && (data->log_stat & LOG_CONS) &&
	    (fd = open(_PATH_CONSOLE, O_WRONLY|O_NONBLOCK, 0)) >= 0) {
		struct iovec iov[2];
		
		p = strchr(tbuf, '>') + 1;
		iov[0].iov_base = p;
		iov[0].iov_len = cnt - (p - tbuf);
		iov[1].iov_base = "\r\n";
		iov[1].iov_len = 2;
		(void)writev(fd, iov, 2);
		(void)close(fd);
	}
}
Пример #14
0
int
main(int argc, char *argv[])
{
	fd_set 		set;
	int 		ch, uflag = 0, p;
	struct passwd  *pw;

	if (geteuid() != 0) {
		(void) fprintf(stderr, "%s: need root privileges\n",
			       __progname);
		exit(1);
	}
	pw = getpwnam("_discardd");
	if (pw == NULL) {
		(void) fprintf(stderr, "%s: no _discardd user\n", __progname);
		exit(1);
	}

	while ((ch = getopt(argc, argv, "u")) != -1) {
		switch (ch) {
		case 'u':
			uflag = 1;
			break;
		default:
			usage();
			/* NOTREACHED */
		}
	}
	argc -= optind;
	argv += optind;

	openlog_r(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON, &sdata);

	/* Start TCP and UDP protocols separately. */
	starttcp();
	if (uflag)
		startudp();

	/* Drop privileges */
	if (chroot("/var/empty") != 0 || chdir("/") != 0) {
		(void) fprintf(stderr, "%s: could not chroot\n", __progname);
		exit(1);
	}
	if (setgroups(1, &pw->pw_gid) ||
	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) {
		(void) fprintf(stderr, "%s: can't drop privileges\n",
			       __progname);
		exit(1);
	}

        if (daemon(0, 0) < 0) {
                (void) fprintf(stderr, "%s: unable to daemonize\n", __progname);
		exit(1);
	}

#ifdef __OpenBSD__
	if ((p = pledge("stdio inet proc", NULL)) == -1) {
		fprintf(stderr, "%s: pledge(2) failed: %s\n", __progname,
			strerror(errno));
		exit(1);
	}
#endif

	signal(SIGCHLD, SIG_IGN);
	signal(SIGUSR1, quit);

	FD_ZERO(&set);

	while (1) {
		FD_SET(tcpfd, &set);
		if (uflag)
			FD_SET(udpfd, &set);

		if (select(MAX(tcpfd, udpfd) + 1, &set, NULL, NULL, NULL) < 0) {
			syslog_r(LOG_ERR, &sdata, "%s", strerror(errno));
			exit(1);
		}

		if (tcpfd > -1 && FD_ISSET(tcpfd, &set))
			discardtcp();

		if (uflag && udpfd > -1 && FD_ISSET(udpfd, &set))
			discardudp();
	}

	return 0;
}
Пример #15
0
int
main(int argc, char *argv[])
{
	int ch, cftest = 0, daemonize = 1, rdomain = -1;
	extern char *__progname;
	char *sync_iface = NULL;
	char *sync_baddr = NULL;
	u_short sync_port = 0;
	struct servent *ent;

	/* Initially, log errors to stderr as well as to syslogd. */
	openlog_r(__progname, LOG_PID | LOG_NDELAY, DHCPD_LOG_FACILITY, &sdata);

	opterr = 0;
	while ((ch = getopt(argc, argv, "A:C:L:c:dfl:nY:y:")) != -1)
		switch (ch) {
		case 'Y':
			syncsend = 1;
			break;
		case 'y':
			syncrecv = 1;
			break;
		}
	if (syncsend || syncrecv) {
		if ((ent = getservbyname("dhcpd-sync", "udp")) == NULL)
			errx(1, "Can't find service \"dhcpd-sync\" in "
			    "/etc/services");
		sync_port = ntohs(ent->s_port);
	}

	optreset = optind = opterr = 1;
	while ((ch = getopt(argc, argv, "A:C:L:c:dfl:nY:y:")) != -1)
		switch (ch) {
		case 'A':
			abandoned_tab = optarg;
			break;
		case 'C':
			changedmac_tab = optarg;
			break;
		case 'L':
			leased_tab = optarg;
			break;
		case 'c':
			path_dhcpd_conf = optarg;
			break;
		case 'd':
			daemonize = 0;
			log_perror = 1;
			break;
		case 'f':
			daemonize = 0;
			break;
		case 'l':
			path_dhcpd_db = optarg;
			break;
		case 'n':
			daemonize = 0;
			cftest = 1;
			log_perror = 1;
			break;
		case 'Y':
			if (sync_addhost(optarg, sync_port) != 0)
				sync_iface = optarg;
			syncsend = 1;
			break;
		case 'y':
			sync_baddr = optarg;
			syncrecv = 1;
			break;
		default:
			usage();
		}

	argc -= optind;
	argv += optind;

	while (argc > 0) {
		struct interface_info *tmp = calloc(1, sizeof(*tmp));
		if (!tmp)
			error("calloc");
		strlcpy(tmp->name, argv[0], sizeof(tmp->name));
		tmp->next = interfaces;
		interfaces = tmp;
		argc--;
		argv++;
	}

	/* Default DHCP/BOOTP ports. */
	server_port = htons(SERVER_PORT);
	client_port = htons(CLIENT_PORT);

	tzset();

	time(&cur_time);
	if (!readconf())
		error("Configuration file errors encountered");

	if (cftest)
		exit(0);

	db_startup();
	discover_interfaces(&rdomain);

	if (rdomain != -1)
		if (setrtable(rdomain) == -1)
			error("setrtable (%m)");

	icmp_startup(1, lease_pinged);

	if (syncsend || syncrecv) {
		syncfd = sync_init(sync_iface, sync_baddr, sync_port);
		if (syncfd == -1)
			err(1, "sync init");
	}

	if ((pw = getpwnam("_dhcp")) == NULL)
		error("user \"_dhcp\" not found");

	if (daemonize)
		daemon(0, 0);

	/* don't go near /dev/pf unless we actually intend to use it */
	if ((abandoned_tab != NULL) ||
	    (changedmac_tab != NULL) ||
	    (leased_tab != NULL)){
		if (pipe(pfpipe) == -1)
			error("pipe (%m)");
		switch (pfproc_pid = fork()){
		case -1:
			error("fork (%m)");
			/* NOTREACHED */
			exit(1);
		case 0:
			/* child process. start up table engine */
			pftable_handler();
			/* NOTREACHED */
			exit(1);
		default:
			gotpipe = 1;
			break;
		}
	}

	if (chroot(_PATH_VAREMPTY) == -1)
		error("chroot %s: %m", _PATH_VAREMPTY);
	if (chdir("/") == -1)
		error("chdir(\"/\"): %m");
	if (setgroups(1, &pw->pw_gid) ||
	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
		error("can't drop privileges: %m");

	bootp_packet_handler = do_packet;
	add_timeout(cur_time + 5, periodic_scan, NULL);
	dispatch();

	/* not reached */
	exit(0);
}