Пример #1
0
static void
control_close(struct ctl_conn *c)
{
	TAILQ_REMOVE(&ctl_conns, c, entry);
	event_del(&c->iev.ev);
	close(c->iev.ibuf.fd);
	imsg_clear(&c->iev.ibuf);
	free(c);

	stat_backend->decrement("control.session", 1);

	if (available_fds(CONTROL_FD_RESERVE))
		return;

	if (!event_pending(&control_state.ev, EV_READ, NULL)) {
		log_warnx("re-enabling ctl connections");
		event_add(&control_state.ev, NULL);
	}
}
Пример #2
0
static void
chld_sighdlr(evutil_socket_t sig, short events, void *args) {
    struct event_base *evbase = args;

    char *name = "unknow";
    (void)events;

    switch (sig)
    {
        case SIGTERM:
            name = "sigterm";
            break;
        case SIGINT:
            name = "sigint";
            break;
    }
    log_warnx("received signal %s(%d), stopping", name, sig);
    event_base_loopbreak(evbase);
}
Пример #3
0
static int
on_rcpt(uint64_t id, const char *rcpt)
{
	char	s_id[20];

	memset(s_id, 0, 20);
	sprintf(s_id, "%lu", id);

	lua_getglobal(L, "on_rcpt");
	lua_pushstring(L, s_id);
	lua_pushstring(L, rcpt);

	if (lua_pcall(L, 2, 0, 0)) {
		log_warnx("warn: filter-lua: on_rcpt() failed: %s", lua_tostring(L, -1));
		exit(1);
	}

	return (1);
}
Пример #4
0
/* Initial state. */
int
fetch_mbox_state_init(struct account *a, struct fetch_ctx *fctx)
{
	struct fetch_mbox_data	*data = a->data;

	if (fetch_mbox_make(a) != 0)
		return (FETCH_ERROR);
	if (ARRAY_EMPTY(&data->fmboxes)) {
		log_warnx("%s: no mboxes found", a->name);
		return (-1);
	}

	data->index = 0;

	TAILQ_INIT(&data->kept);

	fctx->state = fetch_mbox_state_open;
	return (FETCH_AGAIN);
}
Пример #5
0
void xml_finish(struct writer * w) {
	struct xml_writer_private * p = w->priv;
	int failed = 0;

	if (xmlTextWriterEndDocument(p->xw) < 0 ) {
		log_warnx("lldpctl", "cannot finish document");
		failed = 1;
	}

	xmlFreeTextWriter(p->xw);
	
	if ( ! failed )
		xmlSaveFileEnc("-", p->doc, MY_ENCODING);

	xmlFreeDoc(p->doc);

	free( w->priv );
	free( w );
}
Пример #6
0
static void
filter_register_query(uint64_t id, uint64_t qid, int type)
{
	struct filter_session	*s;

	log_trace(TRACE_FILTERS, "filter-api:%s %016"PRIx64" %s", filter_name, id, query_to_str(type));

	s = tree_xget(&sessions, id);
	if (s->qid) {
		log_warnx("warn: filter-api:%s query already in progess",
		    filter_name);
		fatalx("filter-api: exiting");
	}
	s->qid = qid;
	s->qtype = type;
	s->response.ready = 0;

	tree_xset(&queries, qid, s);
}
Пример #7
0
/* Sleep for lock. */
int
locksleep(const char *hdr, const char *path, long long *used)
{
	useconds_t	us;

	if (*used == 0)
		srandom((u_int) getpid());

	us = LOCKSLEEPTIME + (random() % LOCKSLEEPTIME);
	log_debug3("%s: %s: "
	    "sleeping %.3f seconds for lock", hdr, path, us / 1000000.0);
	usleep(us);

	*used += us;
	if (*used < LOCKTOTALTIME)
		return (0);
	log_warnx("%s: %s: "
	    "couldn't get lock in %.3f seconds", hdr, path, *used / 1000000.0);
	return (-1);
}
Пример #8
0
static int
queue_ram_envelope_load(uint64_t evpid, char *buf, size_t len)
{
	struct qr_envelope	*evp;
	struct qr_message	*msg;

	if ((msg = get_message(evpid_to_msgid(evpid))) == NULL)
		return (0);

	if ((evp = tree_get(&msg->envelopes, evpid)) == NULL) {
		log_warn("warn: queue-ram: not found");
		return (0);
	}
	if (len < evp->len) {
		log_warnx("warn: queue-ram: buffer too small");
		return (0);
	}
	memmove(buf, evp->buf, evp->len);
	return (evp->len);
}
Пример #9
0
int
check_http_digest(struct ctl_tcp_event *cte)
{
	char		*head;
	u_char		*b;
	char		 digest[SHA1_DIGEST_STRING_LENGTH];
	struct host	*host;

	/*
	 * ensure string is nul-terminated.
	 */
	b = ibuf_reserve(cte->buf, 1);
	if (b == NULL)
		fatal("out of memory");
	*b = '\0';

	head = cte->buf->buf;
	host = cte->host;
	host->he = HCE_HTTP_DIGEST_ERROR;

	if ((head = strstr(head, "\r\n\r\n")) == NULL) {
		log_debug("%s: %s failed (no end of headers)",
		    __func__, host->conf.name);
		host->up = HOST_DOWN;
		return (1);
	}
	head += strlen("\r\n\r\n");

	digeststr(cte->table->conf.digest_type, head, strlen(head), digest);

	if (strcmp(cte->table->conf.digest, digest)) {
		log_warnx("%s: %s failed (wrong digest)",
		    __func__, host->conf.name);
		host->he = HCE_HTTP_DIGEST_FAIL;
		host->up = HOST_DOWN;
	} else {
		host->he = HCE_HTTP_DIGEST_OK;
		host->up = HOST_UP;
	}
	return (!(host->up == HOST_UP));
}
Пример #10
0
/* ARGSUSED */
static void
control_accept(int listenfd, short event, void *arg)
{
	int			 connfd;
	socklen_t		 len;
	struct sockaddr_un	 sun;
	struct ctl_conn		*c;

	if (getdtablesize() - getdtablecount() < CONTROL_FD_RESERVE)
		goto pause;

	len = sizeof(sun);
	if ((connfd = accept(listenfd, (struct sockaddr *)&sun, &len)) == -1) {
		if (errno == ENFILE || errno == EMFILE)
			goto pause;
		if (errno == EINTR || errno == EWOULDBLOCK ||
		    errno == ECONNABORTED)
			return;
		fatal("control_accept: accept");
	}

	session_socket_blockmode(connfd, BM_NONBLOCK);

	c = xcalloc(1, sizeof(*c), "control_accept");
	if (getpeereid(connfd, &c->euid, &c->egid) == -1)
		fatal("getpeereid");
	c->id = ++connid;
	c->mproc.proc = PROC_CLIENT;
	c->mproc.handler = control_dispatch_ext;
	c->mproc.data = c;
	mproc_init(&c->mproc, connfd);
	mproc_enable(&c->mproc);
	tree_xset(&ctl_conns, c->id, c);

	stat_backend->increment("control.session", 1);
	return;

pause:
	log_warnx("warn: ctl client limit hit, disabling new connections");
	event_del(&control_state.ev);
}
Пример #11
0
int
main(int argc, char **argv)
{
	int	ch, d = 0, v = 0;

	log_init(1);

	while ((ch = getopt(argc, argv, "dv")) != -1) {
		switch (ch) {
		case 'd':
			d = 1;
			break;
		case 'v':
			v |= TRACE_DEBUG;
			break;
		default:
			log_warnx("warn: bad option");
			return (1);
			/* NOTREACHED */
		}
	}
	argc -= optind;
	argv += optind;

	log_init(d);
	log_verbose(v);

	log_debug("debug: starting...");

	filter_api_on_data(clamav_on_data);
	filter_api_on_dataline(clamav_on_dataline);
	filter_api_on_eom(clamav_on_eom);
	filter_api_on_reset(clamav_on_reset);
	filter_api_on_disconnect(clamav_on_disconnect);
	filter_api_on_rollback(clamav_on_rollback);

	filter_api_loop();
	log_debug("debug: exiting");

	return (1);
}
Пример #12
0
static int
queue_proc_envelope_load(uint64_t evpid, char *buf, size_t len)
{
	int	r;

	imsg_compose(&ibuf, PROC_QUEUE_ENVELOPE_LOAD, 0, 0, -1, &evpid,
	    sizeof(evpid));

	queue_proc_call();

	if (rlen > len) {
		log_warnx("warn: queue-proc: buf too small");
		fatalx("queue-proc: exiting");
	}

	r = rlen;
	queue_proc_read(buf, rlen);
	queue_proc_end();

	return (r);
}
Пример #13
0
static int
on_data(uint64_t id)
{
	PyObject *py_args;
	PyObject *py_ret;
	PyObject *py_id;

	py_args = PyTuple_New(1);
	py_id   = PyLong_FromUnsignedLongLong(id);
	PyTuple_SetItem(py_args, 0, py_id);
	py_ret = PyObject_CallObject(py_on_data, py_args);
	Py_DECREF(py_args);

	if (py_ret == NULL) {
		PyErr_Print();
		log_warnx("warn: filter-python: call to on_datra handler failed");
		exit(1);
	}

	return (1);
}
Пример #14
0
static int
on_connect(uint64_t id, struct filter_connect *conn)
{
	char	s_id[20];

	memset(s_id, 0, 20);
	sprintf(s_id, "%lu", id);

	lua_getglobal(L, "on_connect");
	lua_pushstring(L, s_id);
	lua_pushstring(L, filter_api_sockaddr_to_text((struct sockaddr *)&conn->local));
	lua_pushstring(L, filter_api_sockaddr_to_text((struct sockaddr *)&conn->remote));
	lua_pushstring(L, conn->hostname);

	if (lua_pcall(L, 4, 0, 0)) {
		log_warnx("warn: filter-lua: on_connect() failed: %s", lua_tostring(L, -1));
		exit(1);
	}

	return (1);
}
Пример #15
0
static int
queue_ram_message_delete(uint32_t msgid)
{
	struct qr_message	*msg;
	struct qr_envelope	*evp;
	uint64_t		 evpid;

	if ((msg = tree_pop(&messages, msgid)) == NULL) {
		log_warnx("warn: queue-ram: not found");
		return (0);
	}
	while (tree_poproot(&messages, &evpid, (void**)&evp)) {
		stat_decrement("queue.ram.envelope.size", evp->len);
		free(evp->buf);
		free(evp);
	}
	stat_decrement("queue.ram.message.size", msg->len);
	free(msg->buf);
	free(msg);
	return (0);
}
Пример #16
0
void
control_close(int fd)
{
	struct ctl_conn	*c;

	if ((c = control_connbyfd(fd)) == NULL) {
		log_warn("control_close: fd %d: not found", fd);
		return;
	}
	TAILQ_REMOVE(&ctl_conns, c, entry);
	event_del(&c->iev.ev);
	imsg_clear(&c->iev.ibuf);
	close(fd);
	free(c);

	if (stat_decrement(STATS_CONTROL_SESSION) < env->sc_maxconn &&
	    !event_pending(&control_state.ev, EV_READ, NULL)) {
		log_warnx("re-enabling ctl connections");
		event_add(&control_state.ev, NULL);
	}
}
Пример #17
0
/**
 * Read an anoubis protocol message from a client connected to the session
 * engine. A client message on the wire consists of a 32 bit length in
 * network byte order followed by the actual message data. The length
 * given includes the 32 length itself and the 32 bit checksum at the
 * end of the message.
 *
 * @param fd The file descriptor to read from.
 * @param msgp A complete message (if any) is stored here. This value
 *     must never be NULL. The pointer pointed to by msgp is either set
 *     to NULL or is set to point to the result message. The result message
 *     is allocated using anoubis_msg_new and must be freed by the caller
 *     with anoubis_msg_free.
 * @return Zero if EOF is encountered. A negative error code if an error
 *     occured or a positive value in case of success.
 *     NOTE: Success does not mean that there is a complete message
 *     available. The message may still be incomplete. In this case
 *     NULL is stored in *msgp.
 */
int
get_client_msg(int fd, struct anoubis_msg **msgp)
{
	struct msg_buf		*mbp;
	u_int32_t		 len;
	struct anoubis_msg	*m;

	*msgp = NULL;
	if ((mbp = _get_mbp(fd)) == NULL)
		return 0;
	if (mbp->rmsg) {
		log_warnx("get_client_msg: Bad buffer state");
		return 0;
	}
	if ((unsigned int)(mbp->rtailp - mbp->rheadp) < sizeof(len))
		if (!_fill_buf(mbp))
			return 0;
	if ((unsigned int)(mbp->rtailp - mbp->rheadp) < sizeof(len))
		return 1;
	len = ntohl(*(u_int32_t*)mbp->rheadp);
	if ((unsigned int)(mbp->rtailp - mbp->rheadp) < len)
		if (!_fill_buf(mbp))
			return 0;
	if ((unsigned int)(mbp->rtailp - mbp->rheadp) < len)
		return 1;
	/*
	 * anoubis_msg_new expects the size of the message without
	 * the message length and without the trainling checksum (i.e.
	 * payload data only). However, m->length of the resulting
	 * message includes the checksum but not the message length.
	 * This is the reason for the somewhat surprising length calculations.
	 */
	m = anoubis_msg_new(len - sizeof(len) - CSUM_LEN);
	if (!m)
		return -ENOMEM;
	memcpy(m->u.buf, mbp->rheadp+sizeof(len), m->length);
	mbp->rheadp += len;
	*msgp = m;
	return 1;
}
Пример #18
0
static int
chap_b642bin(const char *b64, void **binp, size_t *bin_lenp)
{
    char *bin;
    int b64_len, bin_len;

    b64_len = strlen(b64);
    bin_len = (b64_len + 3) / 4 * 3;
    bin = calloc(bin_len, 1);
    if (bin == NULL)
        log_err(1, "calloc");

    bin_len = b64_pton(b64, bin, bin_len);
    if (bin_len < 0) {
        log_warnx("malformed base64 variable");
        free(bin);
        return (-1);
    }
    *binp = bin;
    *bin_lenp = bin_len;
    return (0);
}
Пример #19
0
/*
 * Copy 'src' to 'dst' until 'marker' is found while unescaping '\'
 * characters. The return value tells the caller where to continue
 * parsing (might be the end of the string) or NULL on error.
 */
static char *
ca_x509_name_unescape(char *src, char *dst, char marker)
{
	while (*src) {
		if (*src == marker) {
			src++;
			break;
		}
		if (*src == '\\') {
			src++;
			if (!*src) {
				log_warnx("%s: '\\' at end of string",
				    __func__);
				*dst = '\0';
				return (NULL);
			}
		}
		*dst++ = *src++;
	}
	*dst = '\0';
	return (src);
}
Пример #20
0
int
host(const char *s, struct bgpd_addr *h, u_int8_t *len)
{
	int			 done = 0;
	int			 mask;
	char			*p, *ps;
	const char		*errstr;

	if ((p = strrchr(s, '/')) != NULL) {
		mask = strtonum(p + 1, 0, 128, &errstr);
		if (errstr) {
			log_warnx("prefixlen is %s: %s", errstr, p + 1);
			return (0);
		}
		if ((ps = malloc(strlen(s) - strlen(p) + 1)) == NULL)
			fatal("host: malloc");
		strlcpy(ps, s, strlen(s) - strlen(p) + 1);
	} else {
		if ((ps = strdup(s)) == NULL)
			fatal("host: strdup");
		mask = 128;
	}

	bzero(h, sizeof(struct bgpd_addr));

	/* IPv4 address? */
	if (!done)
		done = host_v4(s, h, len);

	/* IPv6 address? */
	if (!done) {
		done = host_v6(ps, h);
		*len = mask;
	}

	free(ps);

	return (done);
}
Пример #21
0
static int
clamav_on_eom(uint64_t id, size_t size)
{
	struct clamav *cl;
	int r;

	if ((cl = filter_api_get_udata(id)) == NULL)
		return filter_api_accept(id);
	if (clamav_response(cl) == -1) {
		clamav_clear(cl);
		filter_api_set_udata(id, NULL);
		return filter_api_reject_code(id, FILTER_FAIL, 451, "4.7.1 Virus filter failed");
	}
	r = cl->r;
	clamav_clear(cl);
	filter_api_set_udata(id, NULL);
	if (r) {
		log_warnx("warn: session %016"PRIx64": on_eom: REJECT virus", id);
		return filter_api_reject_code(id, FILTER_CLOSE, 554, "5.7.1 Virus found");
	}
	return filter_api_accept(id);
}
Пример #22
0
void
tcp_send_req(int s, short event, void *arg)
{
	struct ctl_tcp_event	*cte = arg;
	int			 bs;
	int			 len;

	if (event == EV_TIMEOUT) {
		cte->host->up = HOST_DOWN;
		close(cte->s);
		hce_notify_done(cte->host, HCE_TCP_WRITE_TIMEOUT);
		return;
	}
	len = strlen(cte->req);
	do {
		bs = write(s, cte->req, len);
		if (bs == -1) {
			if (errno == EAGAIN || errno == EINTR)
				goto retry;
			log_warnx("%s: cannot send request", __func__);
			cte->host->up = HOST_DOWN;
			close(cte->s);
			hce_notify_done(cte->host, HCE_TCP_WRITE_FAIL);
			return;
		}
		cte->req += bs;
		len -= bs;
	} while (len > 0);

	if ((cte->buf = ibuf_dynamic(SMALL_READ_BUF_SIZE, UINT_MAX)) == NULL)
		fatalx("tcp_send_req: cannot create dynamic buffer");
	event_again(&cte->ev, s, EV_TIMEOUT|EV_READ, tcp_read_buf,
	    &cte->tv_start, &cte->table->conf.timeout, cte);
	return;

 retry:
	event_again(&cte->ev, s, EV_TIMEOUT|EV_WRITE, tcp_send_req,
	    &cte->tv_start, &cte->table->conf.timeout, cte);
}
Пример #23
0
/* Capability state 1. Parse capabilities and set flags. */
int
imap_state_capability1(struct account *a, struct fetch_ctx *fctx)
{
	struct fetch_imap_data	*data = a->data;
	char			*line, *ptr;

	if (imap_getln(a, fctx, IMAP_UNTAGGED, &line) != 0)
		return (FETCH_ERROR);
	if (line == NULL)
		return (FETCH_BLOCK);

	/* Convert to uppercase. */
	for (ptr = line; *ptr != '\0'; ptr++)
		*ptr = toupper((u_char) *ptr);

	if (strstr(line, "IMAP4REV1") == NULL) {
		log_warnx("%s: no IMAP4rev1 capability: %s", a->name, line);
		return (FETCH_ERROR);
	}

	data->capa = 0;
	if (strstr(line, "AUTH=CRAM-MD5") != NULL)
		data->capa |= IMAP_CAPA_AUTH_CRAM_MD5;

	/* Use XYZZY to detect Google brokenness. */
	if (strstr(line, "XYZZY") != NULL)
		data->capa |= IMAP_CAPA_XYZZY;

	/* GMail IMAP extensions. */
	if (strstr(line, "X-GM-EXT-1") != NULL)
		data->capa |= IMAP_CAPA_GMEXT;

	if (strstr(line, "STARTTLS") != NULL)
		data->capa |= IMAP_CAPA_STARTTLS;

	fctx->state = imap_state_capability2;
	return (FETCH_AGAIN);
}
Пример #24
0
int
up_generate(struct rde_peer *peer, struct rde_aspath *asp,
    struct bgpd_addr *addr, u_int8_t prefixlen)
{
	struct update_attr		*ua = NULL;
	struct update_prefix		*up;

	if (asp) {
		ua = calloc(1, sizeof(struct update_attr));
		if (ua == NULL)
			fatal("up_generate");

		if (up_generate_attr(peer, ua, asp, addr->aid) == -1) {
			log_warnx("generation of bgp path attributes failed");
			free(ua);
			return (-1);
		}
		/*
		 * use aspath_hash as attr_hash, this may be unoptimal
		 * but currently I don't care.
		 */
		ua->attr_hash = hash32_buf(ua->attr, ua->attr_len, HASHINIT);
		if (ua->mpattr)
			ua->attr_hash = hash32_buf(ua->mpattr, ua->mpattr_len,
			    ua->attr_hash);
	}

	up = calloc(1, sizeof(struct update_prefix));
	if (up == NULL)
		fatal("up_generate");
	up->prefix = *addr;
	up->prefixlen = prefixlen;

	if (up_add(peer, up, ua) == -1)
		return (-1);

	return (0);
}
Пример #25
0
/* ARGSUSED */
static void
control_accept(int listenfd, short event, void *arg)
{
	int			 connfd;
	socklen_t		 len;
	struct sockaddr_un	 sun;
	struct ctl_conn		*c;

	if (available_fds(CONTROL_FD_RESERVE))
		goto pause;

	len = sizeof(sun);
	if ((connfd = accept(listenfd, (struct sockaddr *)&sun, &len)) == -1) {
		if (errno == ENFILE || errno == EMFILE)
			goto pause;
		if (errno == EINTR || errno == ECONNABORTED)
			return;
		fatal("control_accept: accept");
	}

	session_socket_blockmode(connfd, BM_NONBLOCK);

	c = xcalloc(1, sizeof(*c), "control_accept");
	imsg_init(&c->iev.ibuf, connfd);
	c->iev.handler = control_dispatch_ext;
	c->iev.events = EV_READ;
	event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events,
	    c->iev.handler, NULL);
	event_add(&c->iev.ev, NULL);
	TAILQ_INSERT_TAIL(&ctl_conns, c, entry);

	stat_backend->increment("control.session", 1);
	return;

pause:
	log_warnx("ctl client limit hit, disabling new connections");
	event_del(&control_state.ev);
}
Пример #26
0
static char *
table_postgres_prepare_stmt(PGconn *_db, const char *query, int nparams,
    unsigned int nfields)
{
	static unsigned int	 n = 0;
	PGresult		*res;
	char			*stmt;

	if (asprintf(&stmt, "stmt%u", n++) == -1) {
		log_warn("warn: asprintf");
		return NULL;
	}

	res = PQprepare(_db, stmt, query, nparams, NULL);
	if (PQresultStatus(res) != PGRES_COMMAND_OK) {
		log_warnx("warn: PQprepare: %s", PQerrorMessage(_db));
		free(stmt);
		stmt = NULL;
	}
	PQclear(res);

	return stmt;
}
Пример #27
0
int
main(int argc, char **argv)
{
	int	ch;

	log_init(1);

	while ((ch = getopt(argc, argv, "")) != -1) {
		switch (ch) {
		default:
			log_warnx("warn: queue-null: bad option");
			return (1);
			/* NOTREACHED */
		}
	}
	argc -= optind;
	argv += optind;

	queue_null_init(1);
	queue_api_dispatch();

	return (0);
}
Пример #28
0
/* STARTTLS state. */
int
imap_state_starttls(struct account *a, struct fetch_ctx *fctx)
{
	struct fetch_imap_data	*data = a->data;
	char			*line, *cause;

	if (imap_getln(a, fctx, IMAP_TAGGED, &line) != 0)
		return (FETCH_ERROR);
	if (line == NULL)
		return (FETCH_BLOCK);
	if (!imap_okay(line))
		return (imap_bad(a, line));

	data->io->ssl = makessl(&data->server, data->io->fd,
	    conf.verify_certs && data->server.verify, conf.timeout, &cause);
	if (data->io->ssl == NULL) {
		log_warnx("%s: STARTTLS failed: %s", a->name, cause);
		xfree(cause);
		return (FETCH_ERROR);
	}

	return (imap_pick_auth(a, fctx));
}
Пример #29
0
static int process_stdin(void) {

  char *s = &stdin_cmdline_buf[0];
  int size;
  int status = 0;

  while(fgets(s, STDIN_CMDLINE_BUF_SIZE, stdin) != NULL) {
    size = strlen(s);
    if(s[size - 1] != '\n') {
      status = 1;
      log_warnx("%s", "Line too long");
      break;
    }

    s[size - 1] = '\0';
    --size;

    g.strp = strsplit_recreate(s, g.opt_strsplit_delim,
			       STRSPLIT_FLAG_IGNEMPTY, g.strp);
    if(g.strp == NULL) {
      status = -1;
      log_err(0, "%s", "strsplit_create returned an error.");
      break;
    }

    status = process_stdin_entry();
    if(status != 0)
      break;
  }

  if(g.strp != NULL) {
    strsplit_delete(g.strp);
    g.strp = NULL;
  }

  return(status != 0 ? 1 : 0);
}
Пример #30
0
void
filter_api_loop(void)
{
	if (register_done) {
		log_warnx("warn: filter-api:%s filter_api_loop() already called", filter_name);
		fatalx("filter-api: exiting");
	}

	filter_api_init();

	register_done = 1;

	mproc_enable(&fi.p);

	if (fi.rootpath) {
		if (chroot(fi.rootpath) == -1) {
			log_warn("warn: filter-api:%s chroot", filter_name);
			fatalx("filter-api: exiting");
		}
		if (chdir("/") == -1) {
			log_warn("warn: filter-api:%s chdir", filter_name);
			fatalx("filter-api: exiting");
		}
	}

	if (setgroups(1, &fi.gid) ||
	    setresgid(fi.gid, fi.gid, fi.gid) ||
	    setresuid(fi.uid, fi.uid, fi.uid)) {
		log_warn("warn: filter-api:%s cannot drop privileges", filter_name);
		fatalx("filter-api: exiting");
	}

	if (event_dispatch() < 0) {
		log_warn("warn: filter-api:%s event_dispatch", filter_name);
		fatalx("filter-api: exiting");
	}
}