From 778a2f3ddcd69804ff5e948b8dd119609356501b Mon Sep 17 00:00:00 2001 From: laforge Date: Sun, 2 Oct 2005 16:59:48 +0000 Subject: first step towards automake --- Makefile.am | 14 + filter/Makefile.am | 1 + filter/packet2flow/Makefile.am | 0 filter/raw2packet/Makefile.am | 0 filter/raw2packet/Makefile.in | 30 -- input/Makefile.am | 2 + input/flow/Makefile.am | 7 + input/flow/Makefile.in | 30 -- input/packet/Makefile.am | 7 + input/packet/Makefile.in | 30 -- libipulog/Makefile | 24 - output/Makefile.am | 8 + output/Makefile.in | 30 -- select.c | 99 ---- select.h | 2 - src/Makefile.am | 4 + src/select.c | 99 ++++ src/select.h | 2 + src/ulogd.c | 1008 ++++++++++++++++++++++++++++++++++++++++ ulogd.c | 1008 ---------------------------------------- 20 files changed, 1152 insertions(+), 1253 deletions(-) create mode 100644 Makefile.am create mode 100644 filter/Makefile.am create mode 100644 filter/packet2flow/Makefile.am create mode 100644 filter/raw2packet/Makefile.am delete mode 100644 filter/raw2packet/Makefile.in create mode 100644 input/Makefile.am create mode 100644 input/flow/Makefile.am delete mode 100644 input/flow/Makefile.in create mode 100644 input/packet/Makefile.am delete mode 100644 input/packet/Makefile.in delete mode 100644 libipulog/Makefile create mode 100644 output/Makefile.am delete mode 100644 output/Makefile.in delete mode 100644 select.c delete mode 100644 select.h create mode 100644 src/Makefile.am create mode 100644 src/select.c create mode 100644 src/select.h create mode 100644 src/ulogd.c delete mode 100644 ulogd.c diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..98f971a --- /dev/null +++ b/Makefile.am @@ -0,0 +1,14 @@ + +AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6 + +man_MANS = ulogd.8 + +EXTRA_DIST = $(man_MANS) + +INCLUDES = $(all_includes) -I$(top_srcdir)/include +SUBDIRS = src input filter output +DIST_SUBDIRS = src input filter output + +$(OBJECTS): libtool +libtool: $(LIBTOOL_DEPS) + $(SHELL) ./config.status --recheck diff --git a/filter/Makefile.am b/filter/Makefile.am new file mode 100644 index 0000000..25f2516 --- /dev/null +++ b/filter/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = raw2packet packet2flow diff --git a/filter/packet2flow/Makefile.am b/filter/packet2flow/Makefile.am new file mode 100644 index 0000000..e69de29 diff --git a/filter/raw2packet/Makefile.am b/filter/raw2packet/Makefile.am new file mode 100644 index 0000000..e69de29 diff --git a/filter/raw2packet/Makefile.in b/filter/raw2packet/Makefile.in deleted file mode 100644 index 3efa4de..0000000 --- a/filter/raw2packet/Makefile.in +++ /dev/null @@ -1,30 +0,0 @@ -# -include @top_srcdir@/Rules.make - -CFLAGS+=-I@top_srcdir@ -I@top_srcdir@/libipulog/include -I@top_srcdir@/include -SH_CFLAGS:=$(CFLAGS) -fPIC - -# Normally You should not need to change anything below -# - -SHARED_LIBS=ulogd_raw2packet_BASE.so - -all: $(SHARED_LIBS) - -distrib: - -$(SHARED_LIBS): %.so: %_sh.o - $(LD) -shared -o $@ $< -lc -lpcap - -%_sh.o: %.c - $(CC) $(SH_CFLAGS) -o $@ -c $< - -clean: - $(RM) $(SHARED_LIBS) *.o - -distclean: - $(RM) Makefile - -install: all - $(INSTALL) -m 755 -d $(DESTDIR)$(ULOGD_LIB_PATH) - $(INSTALL) -m 755 *.so $(DESTDIR)$(ULOGD_LIB_PATH) diff --git a/input/Makefile.am b/input/Makefile.am new file mode 100644 index 0000000..77f2838 --- /dev/null +++ b/input/Makefile.am @@ -0,0 +1,2 @@ + +SUBDIRS = packet flow diff --git a/input/flow/Makefile.am b/input/flow/Makefile.am new file mode 100644 index 0000000..474e155 --- /dev/null +++ b/input/flow/Makefile.am @@ -0,0 +1,7 @@ + +CFLAGS=-fPIC -Wall + +lib_LTLIBRARIES = ulogd_inpflow_CTNL.la # ulogd_inpflow_IPFIX.la + +ulogd_inpflow_CTNL_la_SOURCES = ulogd_inpflow_CTNL.c +ulogd_inpflow_IPFIX_la_SOURCES = ulogd_inpflow_IPFIX.c diff --git a/input/flow/Makefile.in b/input/flow/Makefile.in deleted file mode 100644 index ddb20f4..0000000 --- a/input/flow/Makefile.in +++ /dev/null @@ -1,30 +0,0 @@ -# -include @top_srcdir@/Rules.make - -CFLAGS+=-I@top_srcdir@ -I@top_srcdir@/libipulog/include -I@top_srcdir@/include -SH_CFLAGS:=$(CFLAGS) -fPIC - -# Normally You should not need to change anything below -# - -SHARED_LIBS=ulogd_inpflow_CTNL.so - -all: $(SHARED_LIBS) - -distrib: - -$(SHARED_LIBS): %.so: %_sh.o - $(LD) -shared -o $@ $< -lc -lpcap - -%_sh.o: %.c - $(CC) $(SH_CFLAGS) -o $@ -c $< - -clean: - $(RM) $(SHARED_LIBS) *.o - -distclean: - $(RM) Makefile - -install: all - $(INSTALL) -m 755 -d $(DESTDIR)$(ULOGD_LIB_PATH) - $(INSTALL) -m 755 *.so $(DESTDIR)$(ULOGD_LIB_PATH) diff --git a/input/packet/Makefile.am b/input/packet/Makefile.am new file mode 100644 index 0000000..748496b --- /dev/null +++ b/input/packet/Makefile.am @@ -0,0 +1,7 @@ + +CFLAGS=-fPIC -Wall + +lib_LTLIBRARIES = ulogd_inppkt_NFLOG.la ulogd_inppkt_ULOG.la + +ulogd_inppkt_NFLOG_la_SOURCES = ulogd_inppkt_NFLOG.c +ulogd_inppkt_ULOG_la_SOURCES = ulogd_inppkt_ULOG.c diff --git a/input/packet/Makefile.in b/input/packet/Makefile.in deleted file mode 100644 index 78ae382..0000000 --- a/input/packet/Makefile.in +++ /dev/null @@ -1,30 +0,0 @@ -# -include @top_srcdir@/Rules.make - -CFLAGS+=-I@top_srcdir@ -I@top_srcdir@/libipulog/include -I@top_srcdir@/include -SH_CFLAGS:=$(CFLAGS) -fPIC - -# Normally You should not need to change anything below -# - -SHARED_LIBS=ulogd_inppkt_ULOG.so ulogd_inppkt_NFLOG.so - -all: $(SHARED_LIBS) - -distrib: - -$(SHARED_LIBS): %.so: %_sh.o - $(LD) -shared -o $@ $< -lc -lpcap - -%_sh.o: %.c - $(CC) $(SH_CFLAGS) -o $@ -c $< - -clean: - $(RM) $(SHARED_LIBS) *.o - -distclean: - $(RM) Makefile - -install: all - $(INSTALL) -m 755 -d $(DESTDIR)$(ULOGD_LIB_PATH) - $(INSTALL) -m 755 *.so $(DESTDIR)$(ULOGD_LIB_PATH) diff --git a/libipulog/Makefile b/libipulog/Makefile deleted file mode 100644 index ab4d09b..0000000 --- a/libipulog/Makefile +++ /dev/null @@ -1,24 +0,0 @@ -# Generated automatically from Makefile.in by configure. -# - -include ../Rules.make -CFLAGS+=-Iinclude -I/usr/src/linux/include - -libipulog.a: libipulog.o - $(LD) -i $< -o $@ - -distrib: - -ulog_test: ulog_test.c libipulog.a - $(CC) $(CFLAGS) ulog_test.c libipulog.a -o ulog_test - -libipulog.o: libipulog.c - $(CC) $(CFLAGS) -c $< -o $@ - -clean: - $(RM) ulog_test libipulog.o libipulog.a - -distclean: clean - $(RM) Makefile - -install: libipulog.a diff --git a/output/Makefile.am b/output/Makefile.am new file mode 100644 index 0000000..2039bb9 --- /dev/null +++ b/output/Makefile.am @@ -0,0 +1,8 @@ + +lib_LTLIBRARIES = ulogd_output_LOGEMU.la # ulogd_output_OPRINT.la ulogd_output_SYSLOG.la + +ulogd_output_LOGEMU_SOURCES = ulogd_output_LOGEMU.c +ulogd_output_SYSLOG_SOURCES = ulogd_output_SYSLOG.c +ulogd_output_OPRINT_SOURCES = ulogd_output_OPRINT.c + + diff --git a/output/Makefile.in b/output/Makefile.in deleted file mode 100644 index 6641e6a..0000000 --- a/output/Makefile.in +++ /dev/null @@ -1,30 +0,0 @@ -# -include @top_srcdir@/Rules.make - -CFLAGS+=-I@top_srcdir@ -I@top_srcdir@/libipulog/include -I@top_srcdir@/include -SH_CFLAGS:=$(CFLAGS) -fPIC - -# Normally You should not need to change anything below -# - -SHARED_LIBS=ulogd_output_LOGEMU.so - -all: $(SHARED_LIBS) - -distrib: - -$(SHARED_LIBS): %.so: %_sh.o - $(LD) -shared -o $@ $< -lc -lpcap - -%_sh.o: %.c - $(CC) $(SH_CFLAGS) -o $@ -c $< - -clean: - $(RM) $(SHARED_LIBS) *.o - -distclean: - $(RM) Makefile - -install: all - $(INSTALL) -m 755 -d $(DESTDIR)$(ULOGD_LIB_PATH) - $(INSTALL) -m 755 *.so $(DESTDIR)$(ULOGD_LIB_PATH) diff --git a/select.c b/select.c deleted file mode 100644 index 7d7bff9..0000000 --- a/select.c +++ /dev/null @@ -1,99 +0,0 @@ -/* ulogd, Version $LastChangedRevision: 476 $ - * - * $Id: ulogd.c 476 2004-07-23 03:19:35Z laforge $ - * - * userspace logging daemon for the iptables ULOG target - * of the linux 2.4 netfilter subsystem. - * - * (C) 2000-2005 by Harald Welte - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include - -static int maxfd = 0; -static LIST_HEAD(ulogd_fds); - -int ulogd_register_fd(struct ulogd_fd *fd) -{ - int flags; - - /* make FD nonblocking */ - flags = fcntl(fd->fd, F_GETFL); - if (flags < 0) - return -1; - flags |= O_NONBLOCK; - flags = fcntl(fd->fd, F_SETFL, flags); - if (flags < 0) - return -1; - - /* Register FD */ - if (fd->fd > maxfd) - maxfd = fd->fd; - list_add_tail(&fd->list, &ulogd_fds); - - return 0; -} - -void ulogd_unregister_fd(struct ulogd_fd *fd) -{ - list_del(&fd->list); -} - -int ulogd_select_main() -{ - struct ulogd_fd *ufd; - fd_set readset, writeset, exceptset; - int i; - - FD_ZERO(&readset); - FD_ZERO(&writeset); - FD_ZERO(&exceptset); - - /* prepare read and write fdsets */ - list_for_each_entry(ufd, &ulogd_fds, list) { - if (ufd->when & ULOGD_FD_READ) - FD_SET(ufd->fd, &readset); - - if (ufd->when & ULOGD_FD_WRITE) - FD_SET(ufd->fd, &writeset); - - if (ufd->when & ULOGD_FD_EXCEPT) - FD_SET(ufd->fd, &exceptset); - } - - i = select(maxfd, &readset, &writeset, NULL, NULL); - if (i > 0) { - /* call registered callback functions */ - list_for_each_entry(ufd, &ulogd_fds, list) { - int flags = 0; - - if (FD_ISSET(ufd->fd, &readset)) - flags |= ULOGD_FD_READ; - - if (FD_ISSET(ufd->fd, &writeset)) - flags |= ULOGD_FD_WRITE; - - if (FD_ISSET(ufd->fd, &exceptset)) - flags |= ULOGD_FD_EXCEPT; - - if (flags) - ufd->cb(ufd->fd, flags, ufd->data); - } - } - return i; -} diff --git a/select.h b/select.h deleted file mode 100644 index bcfb66d..0000000 --- a/select.h +++ /dev/null @@ -1,2 +0,0 @@ - -extern int ulogd_select_main(); diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..b39bfcb --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,4 @@ +bin_PROGRAMS = ulogd + +ulogd_SOURCES = ulogd.c select.c ../conffile/conffile.c + diff --git a/src/select.c b/src/select.c new file mode 100644 index 0000000..7d7bff9 --- /dev/null +++ b/src/select.c @@ -0,0 +1,99 @@ +/* ulogd, Version $LastChangedRevision: 476 $ + * + * $Id: ulogd.c 476 2004-07-23 03:19:35Z laforge $ + * + * userspace logging daemon for the iptables ULOG target + * of the linux 2.4 netfilter subsystem. + * + * (C) 2000-2005 by Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include + +static int maxfd = 0; +static LIST_HEAD(ulogd_fds); + +int ulogd_register_fd(struct ulogd_fd *fd) +{ + int flags; + + /* make FD nonblocking */ + flags = fcntl(fd->fd, F_GETFL); + if (flags < 0) + return -1; + flags |= O_NONBLOCK; + flags = fcntl(fd->fd, F_SETFL, flags); + if (flags < 0) + return -1; + + /* Register FD */ + if (fd->fd > maxfd) + maxfd = fd->fd; + list_add_tail(&fd->list, &ulogd_fds); + + return 0; +} + +void ulogd_unregister_fd(struct ulogd_fd *fd) +{ + list_del(&fd->list); +} + +int ulogd_select_main() +{ + struct ulogd_fd *ufd; + fd_set readset, writeset, exceptset; + int i; + + FD_ZERO(&readset); + FD_ZERO(&writeset); + FD_ZERO(&exceptset); + + /* prepare read and write fdsets */ + list_for_each_entry(ufd, &ulogd_fds, list) { + if (ufd->when & ULOGD_FD_READ) + FD_SET(ufd->fd, &readset); + + if (ufd->when & ULOGD_FD_WRITE) + FD_SET(ufd->fd, &writeset); + + if (ufd->when & ULOGD_FD_EXCEPT) + FD_SET(ufd->fd, &exceptset); + } + + i = select(maxfd, &readset, &writeset, NULL, NULL); + if (i > 0) { + /* call registered callback functions */ + list_for_each_entry(ufd, &ulogd_fds, list) { + int flags = 0; + + if (FD_ISSET(ufd->fd, &readset)) + flags |= ULOGD_FD_READ; + + if (FD_ISSET(ufd->fd, &writeset)) + flags |= ULOGD_FD_WRITE; + + if (FD_ISSET(ufd->fd, &exceptset)) + flags |= ULOGD_FD_EXCEPT; + + if (flags) + ufd->cb(ufd->fd, flags, ufd->data); + } + } + return i; +} diff --git a/src/select.h b/src/select.h new file mode 100644 index 0000000..bcfb66d --- /dev/null +++ b/src/select.h @@ -0,0 +1,2 @@ + +extern int ulogd_select_main(); diff --git a/src/ulogd.c b/src/ulogd.c new file mode 100644 index 0000000..af6a8f7 --- /dev/null +++ b/src/ulogd.c @@ -0,0 +1,1008 @@ +/* ulogd, Version $LastChangedRevision$ + * + * $Id$ + * + * unified network logging daemon for Linux. + * + * (C) 2000-2005 by Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Modifications: + * 14 Jun 2001 Martin Josefsson + * - added SIGHUP handler for logfile cycling + * + * 10 Feb 2002 Alessandro Bono + * - added support for non-fork mode + * - added support for logging to stdout + * + * 09 Sep 2003 Magnus Boden + * - added support for more flexible multi-section conffile + * + * 20 Apr 2004 Nicolas Pougetoux + * - added suppurt for seteuid() + * + * 22 Jul 2004 Harald Welte + * - major restructuring for flow accounting / ipfix work + * + * 03 Oct 2004 Harald Welte + * - further unification towards generic network event logging + * and support for lnstat + * + * 17 Apr 2005 Harald Welte + * - + */ + +#define ULOGD_VERSION "2.00alpha" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "select.h" +#ifdef DEBUG +#define DEBUGP(format, args...) fprintf(stderr, format, ## args) +#else +#define DEBUGP(format, args...) +#endif + +/* default config parameters, if not changed in configfile */ +#ifndef ULOGD_LOGFILE_DEFAULT +#define ULOGD_LOGFILE_DEFAULT "/var/log/ulogd.log" +#endif + +/* where to look for the config file */ +#ifndef ULOGD_CONFIGFILE +#define ULOGD_CONFIGFILE "/etc/ulogd.conf" +#endif + +#define COPYRIGHT \ + "Copyright (C) 2000-2005 Harald Welte \n" + +/* global variables */ +static FILE *logfile = NULL; /* logfile pointer */ +static int loglevel = 1; /* current loglevel */ +static char *ulogd_configfile = ULOGD_CONFIGFILE; + +/* linked list for all registered interpreters */ +//static struct ulog_interpreter *ulogd_interpreters; + +/* linked list for all registered plugins */ +static LIST_HEAD(ulogd_plugins); +static LIST_HEAD(ulogd_pi_stacks); + +#if 0 +/*********************************************************************** + * INTERPRETER AND KEY HASH FUNCTIONS (new in 0.9) + ***********************************************************************/ + +/* We keep hashtables of interpreters and registered keys. The hash-tables + * are allocated dynamically at program load time. You may control the + e allocation granularity of both hashes (i.e. the amount of hashtable + * entries are allocated at one time) through modification of the constants + * INTERH_ALLOC_GRAN and KEYH_ALLOC_GRAN + */ + +/* allocation granularity */ +#define INTERH_ALLOC_GRAN 5 + +/* hashtable for all registered interpreters */ +static struct ulogd_interpreter **ulogd_interh; + +/* current hashtable size */ +static unsigned int ulogd_interh_ids_alloc; + +/* total number of registered ids */ +static unsigned int ulogd_interh_ids; + +/* allocate a new interpreter id and write it into the interpreter struct */ +static unsigned int interh_allocid(struct ulogd_interpreter *ip) +{ + unsigned int id; + + id = ++ulogd_interh_ids; + + if (id >= ulogd_interh_ids_alloc) { + if (!ulogd_interh) + ulogd_interh = (struct ulogd_interpreter **) + malloc(INTERH_ALLOC_GRAN * + sizeof(struct ulogd_interpreter)); + else + ulogd_interh = (struct ulogd_interpreter **) + realloc(ulogd_interh, + (INTERH_ALLOC_GRAN + + ulogd_interh_ids_alloc) * + sizeof(struct ulogd_interpreter)); + + ulogd_interh_ids_alloc += INTERH_ALLOC_GRAN; + } + + ip->id = id; + ulogd_interh[id] = ip; + return id; +} + +/* get interpreter id by name */ +unsigned int interh_getid(const char *name) +{ + unsigned int i; + for (i = 1; i <= ulogd_interh_ids; i++) + if (!strcmp(name, (ulogd_interh[i])->name)) + return i; + + return 0; +} + +#ifdef DEBUG +/* dump out the contents of the interpreter hash */ +static void interh_dump(void) +{ + unsigned int i; + + for (i = 1; i <= ulogd_interh_ids; i++) + ulogd_log(ULOGD_DEBUG, "ulogd_interh[%d] = %s\n", + i, (ulogd_interh[i])->name); + +} +#endif + +/* key hash allocation granularity */ +#define KEYH_ALLOC_GRAN 20 + +/* hash table for key ids */ +struct ulogd_keyh_entry *ulogd_keyh; + +/* current size of the hashtable */ +static unsigned int ulogd_keyh_ids_alloc; + +/* total number of registered keys */ +static unsigned int ulogd_keyh_ids; + +/* allocate a new key_id */ +static unsigned int keyh_allocid(struct ulogd_interpreter *ip, unsigned int offset, + const char *name) +{ + unsigned int id; + + id = ++ulogd_keyh_ids; + + if (id >= ulogd_keyh_ids_alloc) { + if (!ulogd_keyh) { + ulogd_keyh = (struct ulogd_keyh_entry *) + malloc(KEYH_ALLOC_GRAN * + sizeof(struct ulogd_keyh_entry)); + if (!ulogd_keyh) { + ulogd_log(ULOGD_ERROR, "OOM!\n"); + return 0; + } + } else { + ulogd_keyh = (struct ulogd_keyh_entry *) + realloc(ulogd_keyh, (KEYH_ALLOC_GRAN + +ulogd_keyh_ids_alloc) * + sizeof(struct ulogd_keyh_entry)); + + if (!ulogd_keyh) { + ulogd_log(ULOGD_ERROR, "OOM!\n"); + return 0; + } + } + + ulogd_keyh_ids_alloc += KEYH_ALLOC_GRAN; + } + + ulogd_keyh[id].interp = ip; + ulogd_keyh[id].offset = offset; + ulogd_keyh[id].name = name; + + return id; +} + +#ifdef DEBUG +/* dump the keyhash to standard output */ +static void keyh_dump(void) +{ + unsigned int i; + + printf("dumping keyh\n"); + for (i = 1; i <= ulogd_keyh_ids; i++) + printf("ulogd_keyh[%lu] = %s:%u\n", i, + ulogd_keyh[i].interp->name, ulogd_keyh[i].offset); +} +#endif + +/* get keyid by name */ +unsigned int keyh_getid(const char *name) +{ + unsigned int i; + for (i = 1; i <= ulogd_keyh_ids; i++) + if (!strcmp(name, ulogd_keyh[i].name)) + return i; + + return 0; +} + +/* get key name by keyid */ +char *keyh_getname(unsigned int id) +{ + if (id > ulogd_keyh_ids) { + ulogd_log(ULOGD_NOTICE, + "keyh_getname called with invalid id%u\n", id); + return NULL; + } + + return ulogd_keyh[id].interp->name; +} + +/* get result for given key id. does not check if result valid */ +struct ulogd_iret *keyh_getres(unsigned int id) +{ + struct ulogd_iret *ret; + + if (id > ulogd_keyh_ids) { + ulogd_log(ULOGD_NOTICE, + "keyh_getres called with invalid id %d\n", id); + return NULL; + } + + ret = &ulogd_keyh[id].interp->result[ulogd_keyh[id].offset]; + + return ret; +} + +/*********************************************************************** + * INTERPRETER MANAGEMENT + ***********************************************************************/ + +/* try to lookup a registered interpreter for a given name */ +static struct ulogd_interpreter *find_interpreter(const char *name) +{ + unsigned int id; + + id = interh_getid(name); + if (!id) + return NULL; + + return ulogd_interh[id]; +} + +/* the function called by all interpreter plugins for registering their + * target. */ +void register_interpreter(struct ulogd_interpreter *me) +{ + unsigned int i; + + /* check if we already have an interpreter with this name */ + if (find_interpreter(me->name)) { + ulogd_log(ULOGD_NOTICE, + "interpreter `%s' already registered\n", me->name); + return; + } + + ulogd_log(ULOGD_INFO, "registering interpreter `%s'\n", me->name); + + /* allocate a new interpreter id for it */ + if (!interh_allocid(me)) { + ulogd_log(ULOGD_ERROR, "unable to obtain interh_id for " + "interpreter '%s'\n", me->name); + return; + } + + /* - allocate one keyh_id for each result of this interpreter + * - link the elements to each other */ + for (i = 0; i < me->key_num; i++) { + if (!keyh_allocid(me, i, me->result[i].key)) { + ulogd_log(ULOGD_ERROR, "unable to obtain keyh_id " + "for interpreter %s, key %d", me->name, + me->result[i].key); + continue; + } + if (i != me->key_num - 1) + me->result[i].next = &me->result[i+1]; + } + + /* all work done, we can prepend the new interpreter to the list */ + if (ulogd_interpreters) + me->result[me->key_num - 1].next = + &ulogd_interpreters->result[0]; + me->next = ulogd_interpreters; + ulogd_interpreters = me; +} +#endif + +/*********************************************************************** + * PLUGIN MANAGEMENT + ***********************************************************************/ + +/* try to lookup a registered plugin for a given name */ +static struct ulogd_plugin *find_plugin(const char *name) +{ + struct ulogd_plugin *pl; + + list_for_each_entry(pl, &ulogd_plugins, list) { + if (strcmp(name, pl->name) == 0) + return pl; + } + + return NULL; +} + +/* the function called by all plugins for registering themselves */ +void register_plugin(struct ulogd_plugin *me) +{ + if (find_plugin(me->name)) { + ulogd_log(ULOGD_NOTICE, "plugin `%s' already registered\n", + me->name); + exit(EXIT_FAILURE); + } + ulogd_log(ULOGD_NOTICE, "registering plugin `%s'\n", me->name); + list_add(&me->list, &ulogd_plugins); +} + +/*********************************************************************** + * MAIN PROGRAM + ***********************************************************************/ + +/* log message to the logfile */ +void __ulogd_log(int level, char *file, int line, const char *format, ...) +{ + char *timestr; + va_list ap; + time_t tm; + FILE *outfd; + + /* log only messages which have level at least as high as loglevel */ + if (level < loglevel) + return; + + if (logfile) + outfd = logfile; + else + outfd = stderr; + + va_start(ap, format); + + tm = time(NULL); + timestr = ctime(&tm); + timestr[strlen(timestr)-1] = '\0'; + fprintf(outfd, "%s <%1.1d> %s:%d ", timestr, level, file, line); + + vfprintf(outfd, format, ap); + va_end(ap); + + /* flush glibc's buffer */ + fflush(outfd); +} + +/* propagate results to all downstream plugins in the stack */ +void ulogd_propagate_results(struct ulogd_pluginstance *pi) +{ + struct ulogd_pluginstance *cur = pi; + /* iterate over remaining plugin stack */ + list_for_each_entry_continue(cur, &pi->stack->list, list) { + int ret; + + ret = cur->plugin->interp(cur); + switch (ret) { + case ULOGD_IRET_ERR: + ulogd_log(ULOGD_NOTICE, + "error during propagate_results\n"); + /* fallthrough */ + case ULOGD_IRET_STOP: + /* we shall abort further iteration of the stack */ + return; + case ULOGD_IRET_OK: + /* we shall continue travelling down the stack */ + continue; + default: + ulogd_log(ULOGD_NOTICE, + "unknown return value `%d' from plugin %s\n", + ret, cur->plugin->name); + break; + } + } +} + +#if 0 +/* clean results (set all values to 0 and free pointers) */ +static void clean_results(struct ulogd_iret *ret) +{ + struct ulogd_iret *r; + + for (r = ret; r; r = r->next) { + if (r->flags & ULOGD_RETF_FREE) { + free(r->value.ptr); + r->value.ptr = NULL; + } + memset(&r->value, 0, sizeof(r->value)); + r->flags &= ~ULOGD_RETF_VALID; + } +} +#endif + +static struct ulogd_pluginstance * +pluginstance_alloc_init(struct ulogd_plugin *pl, char *pi_id, + struct ulogd_pluginstance_stack *stack) +{ + unsigned int size; + struct ulogd_pluginstance *pi; + void *ptr; + + size = sizeof(struct ulogd_pluginstance); + size += pl->priv_size; + size += sizeof(struct config_keyset); + size += pl->config_kset->num_ces * sizeof(struct config_entry); + size += pl->input.num_keys * sizeof(struct ulogd_key); + size += pl->output.num_keys * sizeof(struct ulogd_key); + pi = malloc(size); + if (!pi) + return NULL; + + /* initialize */ + memset(pi, 0, size); + INIT_LIST_HEAD(&pi->list); + pi->plugin = pl; + pi->stack = stack; + memcpy(pi->id, pi_id, sizeof(pi->id)); + + ptr = (void *)pi + sizeof(*pi); + + ptr += pl->priv_size; + /* copy config keys */ + pi->config_kset = ptr; + pi->config_kset->num_ces = pl->config_kset->num_ces; + memcpy(pi->config_kset->ces, pl->config_kset->ces, + pi->config_kset->num_ces * sizeof(struct config_entry)); + + /* copy input keys */ + ptr += sizeof(struct config_keyset); + ptr += pi->config_kset->num_ces * sizeof(struct config_entry); + pi->input = ptr; + memcpy(pi->input, pl->input.keys, + pl->input.num_keys * sizeof(struct ulogd_key)); + + /* copy input keys */ + ptr += pl->input.num_keys * sizeof(struct ulogd_key); + pi->output = ptr; + memcpy(pi->output, pl->output.keys, + pl->output.num_keys * sizeof(struct ulogd_key)); + + return pi; +} + + +/* plugin loader to dlopen() a plugins */ +static int load_plugin(char *file) +{ + if (!dlopen(file, RTLD_NOW)) { + ulogd_log(ULOGD_ERROR, "load_plugins: '%s': %s\n", file, + dlerror()); + return 1; + } + return 0; +} + +/* find an output key in a given stack, starting at 'start' */ +static struct ulogd_key * +find_okey_in_stack(char *name, + struct ulogd_pluginstance_stack *stack, + struct ulogd_pluginstance *start) +{ + struct ulogd_pluginstance *pi; + + list_for_each_entry_reverse(pi, &start->list, list) { + int i; + + if ((void *)&pi->list == stack) + return NULL; + + for (i = 0; i < pi->plugin->output.num_keys; i++) { + struct ulogd_key *okey = &pi->output[i]; + if (!strcmp(name, okey->name)) + return okey; + } + } + + return NULL; +} + +/* resolve key connections from bottom to top of stack */ +static int +create_stack_resolve_keys(struct ulogd_pluginstance_stack *stack) +{ + int i = 0; + struct ulogd_pluginstance *pi_cur; + + /* PASS 2: */ + ulogd_log(ULOGD_DEBUG, "connecting input/output keys of stack:\n"); + list_for_each_entry_reverse(pi_cur, &stack->list, list) { + struct ulogd_pluginstance *pi_prev = + list_entry(pi_cur->list.prev, + struct ulogd_pluginstance, + list); + if (i == 0) { + /* first round: output plugin */ + if (pi_cur->plugin->output.type != ULOGD_DTYPE_SINK) { + ulogd_log(ULOGD_ERROR, "last plugin in stack " + "has to be output plugin\n"); + return -EINVAL; + } + /* continue further down */ + } /* no "else' since first could be the last one, too ! */ + + if (&pi_prev->list == &stack->list) { + /* this is the last one in the stack */ + if (pi_cur->plugin->input.type != ULOGD_DTYPE_SOURCE) { + ulogd_log(ULOGD_ERROR, "first plugin in stack " + "has to be source plugin\n"); + return -EINVAL; + } + /* no need to match keys */ + } else { + int j; + + /* not the last one in the stack */ + if (pi_cur->plugin->input.type != + pi_prev->plugin->output.type) { + ulogd_log(ULOGD_ERROR, "type mismatch between " + "%s and %s in stack\n", + pi_cur->plugin->name, + pi_prev->plugin->name); + } + /* call plugin to tell us which keys it requires in + * given configuration */ + if (pi_cur->plugin->configure) { + int ret = pi_cur->plugin->configure(pi_cur, + stack); + if (ret < 0) { + ulogd_log(ULOGD_ERROR, "error during " + "configure of plugin %s\n", + pi_cur->plugin->name); + return ret; + } + } + + for (j = 0; j < pi_cur->plugin->input.num_keys; j++) { + struct ulogd_key *okey; + struct ulogd_key *ikey = + &pi_cur->plugin->input.keys[i]; + + /* skip those marked as 'inactive' by + * pl->configure() */ + if (ikey->flags & ULOGD_KEYF_INACTIVE) + continue; + + if (ikey->u.source) { + ulogd_log(ULOGD_ERROR, "key `%s' " + "already has source\n", + ikey->name); + return -EINVAL; + } + + okey = find_okey_in_stack(ikey->name, + stack, pi_cur); + if (!okey && + !(ikey->flags & ULOGD_KEYF_OPTIONAL)) { + ulogd_log(ULOGD_ERROR, "cannot find " + "key `%s' in stack\n", + ikey->name); + return -EINVAL; + } + + ikey->u.source = okey; + } + } + } + + return 0; +} + +/* create a new stack of plugins */ +static int create_stack(char *option) +{ + struct ulogd_pluginstance_stack *stack; + char *buf = strdup(option); + char *tok; + int ret; + + if (!buf) { + ulogd_log(ULOGD_ERROR, ""); + return 1; + } + + stack = malloc(sizeof(*stack)); + if (!stack) + return -ENOMEM; + INIT_LIST_HEAD(&stack->list); + + ulogd_log(ULOGD_DEBUG, "building new pluginstance stack:\n"); + + /* PASS 1: find and instanciate plugins of stack, link them together */ + for (tok = strtok(buf, ",\n"); tok; tok = strtok(NULL, ",\n")) { + char *plname, *equals; + char pi_id[ULOGD_MAX_KEYLEN]; + struct ulogd_pluginstance *pi; + struct ulogd_plugin *pl; + + /* parse token into sub-tokens */ + equals = strchr(tok, '='); + if (!equals || (equals - tok >= ULOGD_MAX_KEYLEN)) { + ulogd_log(ULOGD_ERROR, "syntax error while parsing `%s'" + "of line `%s'\n", tok, buf); + free(stack); + return -EINVAL; + } + strncpy(pi_id, tok, ULOGD_MAX_KEYLEN-1); + pi_id[equals-tok] = '\0'; + plname = equals+1; + + /* find matching plugin */ + pl = find_plugin(plname); + if (!pl) { + ulogd_log(ULOGD_ERROR, "can't find requested plugin " + "%s\n", plname); + free(stack); + return -ENODEV; + } + + /* allocate */ + pi = pluginstance_alloc_init(pl, pi_id, stack); + if (!pi) { + ulogd_log(ULOGD_ERROR, + "unable to allocate pluginstance for %s\n", + pi_id); + free(stack); + return -ENOMEM; + } + + /* FIXME: call constructor routine from end to beginning, + * fix up input/output keys */ + + ulogd_log(ULOGD_DEBUG, "pushing `%s' on stack\n", pl->name); + list_add(&pi->list, &stack->list); + } + + ret = create_stack_resolve_keys(stack); + if (ret < 0) { + free(stack); + return ret; + } + + /* add head of pluginstance stack to list of stacks */ + list_add(&stack->stack_list, &ulogd_pi_stacks); + return 0; +} + + +static int ulogd_main_loop(void) +{ + int ret = 0; + + while (1) { + ret = ulogd_select_main(); + if (ret == 0) + continue; + + if (ret < 0) { + if (errno == -EINTR) + continue; + else { + ulogd_log(ULOGD_ERROR, "select returned %s\n", + strerror(errno)); + break; + } + } + } + + return ret; +} + +/* open the logfile */ +static int logfile_open(const char *name) +{ + if (!strcmp(name,"stdout")) { + logfile = stdout; + } else { + logfile = fopen(name, "a"); + if (!logfile) { + fprintf(stderr, "ERROR: can't open logfile %s: %s\n", + name, strerror(errno)); + exit(2); + } + } + ulogd_log(ULOGD_INFO, "ulogd Version %s starting\n", ULOGD_VERSION); + return 0; +} + +/* wrapper to handle conffile error codes */ +static int parse_conffile(const char *section, struct config_keyset *ce) +{ + int err; + + err = config_parse_file(section, ce); + + switch(err) { + case 0: + return 0; + break; + case -ERROPEN: + ulogd_log(ULOGD_ERROR, + "unable to open configfile: %s\n", + ulogd_configfile); + break; + case -ERRMAND: + ulogd_log(ULOGD_ERROR, + "mandatory option \"%s\" not found\n", + config_errce->key); + break; + case -ERRMULT: + ulogd_log(ULOGD_ERROR, + "option \"%s\" occurred more than once\n", + config_errce->key); + break; + case -ERRUNKN: + ulogd_log(ULOGD_ERROR, + "unknown config key \"%s\"\n", + config_errce->key); + break; + case -ERRSECTION: + ulogd_log(ULOGD_ERROR, + "section \"%s\" not found\n", section); + break; + } + return 1; + +} + + +static struct config_keyset ulogd_kset = { + .num_ces = 4, + .ces = { + { + .key = "logfile", + .type = CONFIG_TYPE_STRING, + .options = CONFIG_OPT_NONE, + .u.string = ULOGD_LOGFILE_DEFAULT, + }, + { + .key = "plugin", + .type = CONFIG_TYPE_CALLBACK, + .options = CONFIG_OPT_MULTI, + .u.parser = &load_plugin, + }, + { + .key = "loglevel", + .type = CONFIG_TYPE_INT, + .options = CONFIG_OPT_NONE, + .u.value = 1, + }, + { + .key = "stack", + .type = CONFIG_TYPE_CALLBACK, + .options = CONFIG_OPT_NONE, + .u.parser = &create_stack, + }, + }, +}; + +#define logfile_ce ulogd_kset.ces[0] +#define plugin_ce ulogd_kset.ces[1] +#define loglevel_ce ulogd_kset.ces[2] +#define stack_ce ulogd_kset.ces[3] + + +static void deliver_signal_pluginstances(int signal) +{ + struct ulogd_pluginstance_stack *stack; + struct ulogd_pluginstance *pi; + + list_for_each_entry(stack, &ulogd_pi_stacks, stack_list) { + list_for_each_entry(pi, &stack->list, list) { + if (pi->plugin->signal) + (*pi->plugin->signal)(pi, signal); + } + } +} + +static void sigterm_handler(int signal) +{ + + ulogd_log(ULOGD_NOTICE, "sigterm received, exiting\n"); + + deliver_signal_pluginstances(signal); + + if (logfile != stdout) + fclose(logfile); + + exit(0); +} + +static void signal_handler(int signal) +{ + ulogd_log(ULOGD_NOTICE, "signal received, calling pluginstances\n"); + + deliver_signal_pluginstances(signal); + + /* reopen logfile */ + if (logfile != stdout) { + fclose(logfile); + logfile = fopen(logfile_ce.u.string, "a"); + if (!logfile) + sigterm_handler(signal); + } +} + +static void print_usage(void) +{ + /* FIXME */ + printf("ulogd Version %s\n", ULOGD_VERSION); + printf(COPYRIGHT); + printf("This is free software with ABSOLUTELY NO WARRANTY.\n\n"); + printf("Parameters:\n"); + printf("\t-h --help\tThis help page\n"); + printf("\t-V --version\tPrint version information\n"); + printf("\t-d --daemon\tDaemonize (fork into background)\n"); + printf("\t-c --configfile\tUse alternative Configfile\n"); + printf("\t-u --uid\tChange UID/GID\n"); +} + +static struct option opts[] = { + { "version", 0, NULL, 'V' }, + { "daemon", 0, NULL, 'd' }, + { "help", 0, NULL, 'h' }, + { "configfile", 1, NULL, 'c'}, + { "uid", 1, NULL, 'u' }, + { 0 } +}; + +int main(int argc, char* argv[]) +{ + int argch; + int daemonize = 0; + int change_uid = 0; + char *user = NULL; + struct passwd *pw; + uid_t uid = 0; + gid_t gid = 0; + + + while ((argch = getopt_long(argc, argv, "c:dh::Vu:", opts, NULL)) != -1) { + switch (argch) { + default: + case '?': + if (isprint(optopt)) + fprintf(stderr, "Unknown option `-%c'.\n", + optopt); + else + fprintf(stderr, "Unknown option character " + "`\\x%x'.\n", optopt); + + print_usage(); + exit(1); + break; + case 'h': + print_usage(); + exit(0); + break; + case 'd': + daemonize = 1; + break; + case 'V': + printf("ulogd Version %s\n", ULOGD_VERSION); + printf(COPYRIGHT); + exit(0); + break; + case 'c': + ulogd_configfile = optarg; + break; + case 'u': + change_uid = 1; + user = strdup(optarg); + pw = getpwnam(user); + if (!pw) { + printf("Unknown user %s.\n", user); + free(user); + exit(1); + } + uid = pw->pw_uid; + gid = pw->pw_gid; + break; + } + } + + if (config_register_file(ulogd_configfile)) { + ulogd_log(ULOGD_FATAL, "error registering configfile \"%s\"\n", + ulogd_configfile); + exit(1); + } + + /* parse config file */ + if (parse_conffile("global", &ulogd_kset)) { + ulogd_log(ULOGD_FATAL, "parse_conffile\n"); + exit(1); + } + + if (change_uid) { + ulogd_log(ULOGD_NOTICE, "Changing UID / GID\n"); + if (setgid(gid)) { + ulogd_log(ULOGD_FATAL, "can't set GID %u\n", gid); + ipulog_perror(NULL); + exit(1); + } + if (setegid(gid)) { + ulogd_log(ULOGD_FATAL, "can't sett effective GID %u\n", + gid); + ipulog_perror(NULL); + exit(1); + } + if (initgroups(user, gid)) { + ulogd_log(ULOGD_FATAL, "can't set user secondary GID\n"); + ipulog_perror(NULL); + exit(1); + } + if (setuid(uid)) { + ulogd_log(ULOGD_FATAL, "can't set UID %u\n", uid); + ipulog_perror(NULL); + exit(1); + } + if (seteuid(uid)) { + ulogd_log(ULOGD_FATAL, "can't set effective UID %u\n", + uid); + ipulog_perror(NULL); + exit(1); + } + } + + logfile_open(logfile_ce.u.string); + +#ifdef DEBUG + /* dump key and interpreter hash */ + interh_dump(); + keyh_dump(); +#endif + if (daemonize){ + if (fork()) { + exit(0); + } + if (logfile != stdout) + fclose(stdout); + fclose(stderr); + fclose(stdin); + setsid(); + } + + signal(SIGTERM, &sigterm_handler); + signal(SIGHUP, &signal_handler); + + ulogd_log(ULOGD_NOTICE, + "initialization finished, entering main loop\n"); + + ulogd_main_loop(); + + /* hackish, but result is the same */ + sigterm_handler(SIGTERM); + return(0); +} diff --git a/ulogd.c b/ulogd.c deleted file mode 100644 index af6a8f7..0000000 --- a/ulogd.c +++ /dev/null @@ -1,1008 +0,0 @@ -/* ulogd, Version $LastChangedRevision$ - * - * $Id$ - * - * unified network logging daemon for Linux. - * - * (C) 2000-2005 by Harald Welte - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Modifications: - * 14 Jun 2001 Martin Josefsson - * - added SIGHUP handler for logfile cycling - * - * 10 Feb 2002 Alessandro Bono - * - added support for non-fork mode - * - added support for logging to stdout - * - * 09 Sep 2003 Magnus Boden - * - added support for more flexible multi-section conffile - * - * 20 Apr 2004 Nicolas Pougetoux - * - added suppurt for seteuid() - * - * 22 Jul 2004 Harald Welte - * - major restructuring for flow accounting / ipfix work - * - * 03 Oct 2004 Harald Welte - * - further unification towards generic network event logging - * and support for lnstat - * - * 17 Apr 2005 Harald Welte - * - - */ - -#define ULOGD_VERSION "2.00alpha" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "select.h" -#ifdef DEBUG -#define DEBUGP(format, args...) fprintf(stderr, format, ## args) -#else -#define DEBUGP(format, args...) -#endif - -/* default config parameters, if not changed in configfile */ -#ifndef ULOGD_LOGFILE_DEFAULT -#define ULOGD_LOGFILE_DEFAULT "/var/log/ulogd.log" -#endif - -/* where to look for the config file */ -#ifndef ULOGD_CONFIGFILE -#define ULOGD_CONFIGFILE "/etc/ulogd.conf" -#endif - -#define COPYRIGHT \ - "Copyright (C) 2000-2005 Harald Welte \n" - -/* global variables */ -static FILE *logfile = NULL; /* logfile pointer */ -static int loglevel = 1; /* current loglevel */ -static char *ulogd_configfile = ULOGD_CONFIGFILE; - -/* linked list for all registered interpreters */ -//static struct ulog_interpreter *ulogd_interpreters; - -/* linked list for all registered plugins */ -static LIST_HEAD(ulogd_plugins); -static LIST_HEAD(ulogd_pi_stacks); - -#if 0 -/*********************************************************************** - * INTERPRETER AND KEY HASH FUNCTIONS (new in 0.9) - ***********************************************************************/ - -/* We keep hashtables of interpreters and registered keys. The hash-tables - * are allocated dynamically at program load time. You may control the - e allocation granularity of both hashes (i.e. the amount of hashtable - * entries are allocated at one time) through modification of the constants - * INTERH_ALLOC_GRAN and KEYH_ALLOC_GRAN - */ - -/* allocation granularity */ -#define INTERH_ALLOC_GRAN 5 - -/* hashtable for all registered interpreters */ -static struct ulogd_interpreter **ulogd_interh; - -/* current hashtable size */ -static unsigned int ulogd_interh_ids_alloc; - -/* total number of registered ids */ -static unsigned int ulogd_interh_ids; - -/* allocate a new interpreter id and write it into the interpreter struct */ -static unsigned int interh_allocid(struct ulogd_interpreter *ip) -{ - unsigned int id; - - id = ++ulogd_interh_ids; - - if (id >= ulogd_interh_ids_alloc) { - if (!ulogd_interh) - ulogd_interh = (struct ulogd_interpreter **) - malloc(INTERH_ALLOC_GRAN * - sizeof(struct ulogd_interpreter)); - else - ulogd_interh = (struct ulogd_interpreter **) - realloc(ulogd_interh, - (INTERH_ALLOC_GRAN + - ulogd_interh_ids_alloc) * - sizeof(struct ulogd_interpreter)); - - ulogd_interh_ids_alloc += INTERH_ALLOC_GRAN; - } - - ip->id = id; - ulogd_interh[id] = ip; - return id; -} - -/* get interpreter id by name */ -unsigned int interh_getid(const char *name) -{ - unsigned int i; - for (i = 1; i <= ulogd_interh_ids; i++) - if (!strcmp(name, (ulogd_interh[i])->name)) - return i; - - return 0; -} - -#ifdef DEBUG -/* dump out the contents of the interpreter hash */ -static void interh_dump(void) -{ - unsigned int i; - - for (i = 1; i <= ulogd_interh_ids; i++) - ulogd_log(ULOGD_DEBUG, "ulogd_interh[%d] = %s\n", - i, (ulogd_interh[i])->name); - -} -#endif - -/* key hash allocation granularity */ -#define KEYH_ALLOC_GRAN 20 - -/* hash table for key ids */ -struct ulogd_keyh_entry *ulogd_keyh; - -/* current size of the hashtable */ -static unsigned int ulogd_keyh_ids_alloc; - -/* total number of registered keys */ -static unsigned int ulogd_keyh_ids; - -/* allocate a new key_id */ -static unsigned int keyh_allocid(struct ulogd_interpreter *ip, unsigned int offset, - const char *name) -{ - unsigned int id; - - id = ++ulogd_keyh_ids; - - if (id >= ulogd_keyh_ids_alloc) { - if (!ulogd_keyh) { - ulogd_keyh = (struct ulogd_keyh_entry *) - malloc(KEYH_ALLOC_GRAN * - sizeof(struct ulogd_keyh_entry)); - if (!ulogd_keyh) { - ulogd_log(ULOGD_ERROR, "OOM!\n"); - return 0; - } - } else { - ulogd_keyh = (struct ulogd_keyh_entry *) - realloc(ulogd_keyh, (KEYH_ALLOC_GRAN - +ulogd_keyh_ids_alloc) * - sizeof(struct ulogd_keyh_entry)); - - if (!ulogd_keyh) { - ulogd_log(ULOGD_ERROR, "OOM!\n"); - return 0; - } - } - - ulogd_keyh_ids_alloc += KEYH_ALLOC_GRAN; - } - - ulogd_keyh[id].interp = ip; - ulogd_keyh[id].offset = offset; - ulogd_keyh[id].name = name; - - return id; -} - -#ifdef DEBUG -/* dump the keyhash to standard output */ -static void keyh_dump(void) -{ - unsigned int i; - - printf("dumping keyh\n"); - for (i = 1; i <= ulogd_keyh_ids; i++) - printf("ulogd_keyh[%lu] = %s:%u\n", i, - ulogd_keyh[i].interp->name, ulogd_keyh[i].offset); -} -#endif - -/* get keyid by name */ -unsigned int keyh_getid(const char *name) -{ - unsigned int i; - for (i = 1; i <= ulogd_keyh_ids; i++) - if (!strcmp(name, ulogd_keyh[i].name)) - return i; - - return 0; -} - -/* get key name by keyid */ -char *keyh_getname(unsigned int id) -{ - if (id > ulogd_keyh_ids) { - ulogd_log(ULOGD_NOTICE, - "keyh_getname called with invalid id%u\n", id); - return NULL; - } - - return ulogd_keyh[id].interp->name; -} - -/* get result for given key id. does not check if result valid */ -struct ulogd_iret *keyh_getres(unsigned int id) -{ - struct ulogd_iret *ret; - - if (id > ulogd_keyh_ids) { - ulogd_log(ULOGD_NOTICE, - "keyh_getres called with invalid id %d\n", id); - return NULL; - } - - ret = &ulogd_keyh[id].interp->result[ulogd_keyh[id].offset]; - - return ret; -} - -/*********************************************************************** - * INTERPRETER MANAGEMENT - ***********************************************************************/ - -/* try to lookup a registered interpreter for a given name */ -static struct ulogd_interpreter *find_interpreter(const char *name) -{ - unsigned int id; - - id = interh_getid(name); - if (!id) - return NULL; - - return ulogd_interh[id]; -} - -/* the function called by all interpreter plugins for registering their - * target. */ -void register_interpreter(struct ulogd_interpreter *me) -{ - unsigned int i; - - /* check if we already have an interpreter with this name */ - if (find_interpreter(me->name)) { - ulogd_log(ULOGD_NOTICE, - "interpreter `%s' already registered\n", me->name); - return; - } - - ulogd_log(ULOGD_INFO, "registering interpreter `%s'\n", me->name); - - /* allocate a new interpreter id for it */ - if (!interh_allocid(me)) { - ulogd_log(ULOGD_ERROR, "unable to obtain interh_id for " - "interpreter '%s'\n", me->name); - return; - } - - /* - allocate one keyh_id for each result of this interpreter - * - link the elements to each other */ - for (i = 0; i < me->key_num; i++) { - if (!keyh_allocid(me, i, me->result[i].key)) { - ulogd_log(ULOGD_ERROR, "unable to obtain keyh_id " - "for interpreter %s, key %d", me->name, - me->result[i].key); - continue; - } - if (i != me->key_num - 1) - me->result[i].next = &me->result[i+1]; - } - - /* all work done, we can prepend the new interpreter to the list */ - if (ulogd_interpreters) - me->result[me->key_num - 1].next = - &ulogd_interpreters->result[0]; - me->next = ulogd_interpreters; - ulogd_interpreters = me; -} -#endif - -/*********************************************************************** - * PLUGIN MANAGEMENT - ***********************************************************************/ - -/* try to lookup a registered plugin for a given name */ -static struct ulogd_plugin *find_plugin(const char *name) -{ - struct ulogd_plugin *pl; - - list_for_each_entry(pl, &ulogd_plugins, list) { - if (strcmp(name, pl->name) == 0) - return pl; - } - - return NULL; -} - -/* the function called by all plugins for registering themselves */ -void register_plugin(struct ulogd_plugin *me) -{ - if (find_plugin(me->name)) { - ulogd_log(ULOGD_NOTICE, "plugin `%s' already registered\n", - me->name); - exit(EXIT_FAILURE); - } - ulogd_log(ULOGD_NOTICE, "registering plugin `%s'\n", me->name); - list_add(&me->list, &ulogd_plugins); -} - -/*********************************************************************** - * MAIN PROGRAM - ***********************************************************************/ - -/* log message to the logfile */ -void __ulogd_log(int level, char *file, int line, const char *format, ...) -{ - char *timestr; - va_list ap; - time_t tm; - FILE *outfd; - - /* log only messages which have level at least as high as loglevel */ - if (level < loglevel) - return; - - if (logfile) - outfd = logfile; - else - outfd = stderr; - - va_start(ap, format); - - tm = time(NULL); - timestr = ctime(&tm); - timestr[strlen(timestr)-1] = '\0'; - fprintf(outfd, "%s <%1.1d> %s:%d ", timestr, level, file, line); - - vfprintf(outfd, format, ap); - va_end(ap); - - /* flush glibc's buffer */ - fflush(outfd); -} - -/* propagate results to all downstream plugins in the stack */ -void ulogd_propagate_results(struct ulogd_pluginstance *pi) -{ - struct ulogd_pluginstance *cur = pi; - /* iterate over remaining plugin stack */ - list_for_each_entry_continue(cur, &pi->stack->list, list) { - int ret; - - ret = cur->plugin->interp(cur); - switch (ret) { - case ULOGD_IRET_ERR: - ulogd_log(ULOGD_NOTICE, - "error during propagate_results\n"); - /* fallthrough */ - case ULOGD_IRET_STOP: - /* we shall abort further iteration of the stack */ - return; - case ULOGD_IRET_OK: - /* we shall continue travelling down the stack */ - continue; - default: - ulogd_log(ULOGD_NOTICE, - "unknown return value `%d' from plugin %s\n", - ret, cur->plugin->name); - break; - } - } -} - -#if 0 -/* clean results (set all values to 0 and free pointers) */ -static void clean_results(struct ulogd_iret *ret) -{ - struct ulogd_iret *r; - - for (r = ret; r; r = r->next) { - if (r->flags & ULOGD_RETF_FREE) { - free(r->value.ptr); - r->value.ptr = NULL; - } - memset(&r->value, 0, sizeof(r->value)); - r->flags &= ~ULOGD_RETF_VALID; - } -} -#endif - -static struct ulogd_pluginstance * -pluginstance_alloc_init(struct ulogd_plugin *pl, char *pi_id, - struct ulogd_pluginstance_stack *stack) -{ - unsigned int size; - struct ulogd_pluginstance *pi; - void *ptr; - - size = sizeof(struct ulogd_pluginstance); - size += pl->priv_size; - size += sizeof(struct config_keyset); - size += pl->config_kset->num_ces * sizeof(struct config_entry); - size += pl->input.num_keys * sizeof(struct ulogd_key); - size += pl->output.num_keys * sizeof(struct ulogd_key); - pi = malloc(size); - if (!pi) - return NULL; - - /* initialize */ - memset(pi, 0, size); - INIT_LIST_HEAD(&pi->list); - pi->plugin = pl; - pi->stack = stack; - memcpy(pi->id, pi_id, sizeof(pi->id)); - - ptr = (void *)pi + sizeof(*pi); - - ptr += pl->priv_size; - /* copy config keys */ - pi->config_kset = ptr; - pi->config_kset->num_ces = pl->config_kset->num_ces; - memcpy(pi->config_kset->ces, pl->config_kset->ces, - pi->config_kset->num_ces * sizeof(struct config_entry)); - - /* copy input keys */ - ptr += sizeof(struct config_keyset); - ptr += pi->config_kset->num_ces * sizeof(struct config_entry); - pi->input = ptr; - memcpy(pi->input, pl->input.keys, - pl->input.num_keys * sizeof(struct ulogd_key)); - - /* copy input keys */ - ptr += pl->input.num_keys * sizeof(struct ulogd_key); - pi->output = ptr; - memcpy(pi->output, pl->output.keys, - pl->output.num_keys * sizeof(struct ulogd_key)); - - return pi; -} - - -/* plugin loader to dlopen() a plugins */ -static int load_plugin(char *file) -{ - if (!dlopen(file, RTLD_NOW)) { - ulogd_log(ULOGD_ERROR, "load_plugins: '%s': %s\n", file, - dlerror()); - return 1; - } - return 0; -} - -/* find an output key in a given stack, starting at 'start' */ -static struct ulogd_key * -find_okey_in_stack(char *name, - struct ulogd_pluginstance_stack *stack, - struct ulogd_pluginstance *start) -{ - struct ulogd_pluginstance *pi; - - list_for_each_entry_reverse(pi, &start->list, list) { - int i; - - if ((void *)&pi->list == stack) - return NULL; - - for (i = 0; i < pi->plugin->output.num_keys; i++) { - struct ulogd_key *okey = &pi->output[i]; - if (!strcmp(name, okey->name)) - return okey; - } - } - - return NULL; -} - -/* resolve key connections from bottom to top of stack */ -static int -create_stack_resolve_keys(struct ulogd_pluginstance_stack *stack) -{ - int i = 0; - struct ulogd_pluginstance *pi_cur; - - /* PASS 2: */ - ulogd_log(ULOGD_DEBUG, "connecting input/output keys of stack:\n"); - list_for_each_entry_reverse(pi_cur, &stack->list, list) { - struct ulogd_pluginstance *pi_prev = - list_entry(pi_cur->list.prev, - struct ulogd_pluginstance, - list); - if (i == 0) { - /* first round: output plugin */ - if (pi_cur->plugin->output.type != ULOGD_DTYPE_SINK) { - ulogd_log(ULOGD_ERROR, "last plugin in stack " - "has to be output plugin\n"); - return -EINVAL; - } - /* continue further down */ - } /* no "else' since first could be the last one, too ! */ - - if (&pi_prev->list == &stack->list) { - /* this is the last one in the stack */ - if (pi_cur->plugin->input.type != ULOGD_DTYPE_SOURCE) { - ulogd_log(ULOGD_ERROR, "first plugin in stack " - "has to be source plugin\n"); - return -EINVAL; - } - /* no need to match keys */ - } else { - int j; - - /* not the last one in the stack */ - if (pi_cur->plugin->input.type != - pi_prev->plugin->output.type) { - ulogd_log(ULOGD_ERROR, "type mismatch between " - "%s and %s in stack\n", - pi_cur->plugin->name, - pi_prev->plugin->name); - } - /* call plugin to tell us which keys it requires in - * given configuration */ - if (pi_cur->plugin->configure) { - int ret = pi_cur->plugin->configure(pi_cur, - stack); - if (ret < 0) { - ulogd_log(ULOGD_ERROR, "error during " - "configure of plugin %s\n", - pi_cur->plugin->name); - return ret; - } - } - - for (j = 0; j < pi_cur->plugin->input.num_keys; j++) { - struct ulogd_key *okey; - struct ulogd_key *ikey = - &pi_cur->plugin->input.keys[i]; - - /* skip those marked as 'inactive' by - * pl->configure() */ - if (ikey->flags & ULOGD_KEYF_INACTIVE) - continue; - - if (ikey->u.source) { - ulogd_log(ULOGD_ERROR, "key `%s' " - "already has source\n", - ikey->name); - return -EINVAL; - } - - okey = find_okey_in_stack(ikey->name, - stack, pi_cur); - if (!okey && - !(ikey->flags & ULOGD_KEYF_OPTIONAL)) { - ulogd_log(ULOGD_ERROR, "cannot find " - "key `%s' in stack\n", - ikey->name); - return -EINVAL; - } - - ikey->u.source = okey; - } - } - } - - return 0; -} - -/* create a new stack of plugins */ -static int create_stack(char *option) -{ - struct ulogd_pluginstance_stack *stack; - char *buf = strdup(option); - char *tok; - int ret; - - if (!buf) { - ulogd_log(ULOGD_ERROR, ""); - return 1; - } - - stack = malloc(sizeof(*stack)); - if (!stack) - return -ENOMEM; - INIT_LIST_HEAD(&stack->list); - - ulogd_log(ULOGD_DEBUG, "building new pluginstance stack:\n"); - - /* PASS 1: find and instanciate plugins of stack, link them together */ - for (tok = strtok(buf, ",\n"); tok; tok = strtok(NULL, ",\n")) { - char *plname, *equals; - char pi_id[ULOGD_MAX_KEYLEN]; - struct ulogd_pluginstance *pi; - struct ulogd_plugin *pl; - - /* parse token into sub-tokens */ - equals = strchr(tok, '='); - if (!equals || (equals - tok >= ULOGD_MAX_KEYLEN)) { - ulogd_log(ULOGD_ERROR, "syntax error while parsing `%s'" - "of line `%s'\n", tok, buf); - free(stack); - return -EINVAL; - } - strncpy(pi_id, tok, ULOGD_MAX_KEYLEN-1); - pi_id[equals-tok] = '\0'; - plname = equals+1; - - /* find matching plugin */ - pl = find_plugin(plname); - if (!pl) { - ulogd_log(ULOGD_ERROR, "can't find requested plugin " - "%s\n", plname); - free(stack); - return -ENODEV; - } - - /* allocate */ - pi = pluginstance_alloc_init(pl, pi_id, stack); - if (!pi) { - ulogd_log(ULOGD_ERROR, - "unable to allocate pluginstance for %s\n", - pi_id); - free(stack); - return -ENOMEM; - } - - /* FIXME: call constructor routine from end to beginning, - * fix up input/output keys */ - - ulogd_log(ULOGD_DEBUG, "pushing `%s' on stack\n", pl->name); - list_add(&pi->list, &stack->list); - } - - ret = create_stack_resolve_keys(stack); - if (ret < 0) { - free(stack); - return ret; - } - - /* add head of pluginstance stack to list of stacks */ - list_add(&stack->stack_list, &ulogd_pi_stacks); - return 0; -} - - -static int ulogd_main_loop(void) -{ - int ret = 0; - - while (1) { - ret = ulogd_select_main(); - if (ret == 0) - continue; - - if (ret < 0) { - if (errno == -EINTR) - continue; - else { - ulogd_log(ULOGD_ERROR, "select returned %s\n", - strerror(errno)); - break; - } - } - } - - return ret; -} - -/* open the logfile */ -static int logfile_open(const char *name) -{ - if (!strcmp(name,"stdout")) { - logfile = stdout; - } else { - logfile = fopen(name, "a"); - if (!logfile) { - fprintf(stderr, "ERROR: can't open logfile %s: %s\n", - name, strerror(errno)); - exit(2); - } - } - ulogd_log(ULOGD_INFO, "ulogd Version %s starting\n", ULOGD_VERSION); - return 0; -} - -/* wrapper to handle conffile error codes */ -static int parse_conffile(const char *section, struct config_keyset *ce) -{ - int err; - - err = config_parse_file(section, ce); - - switch(err) { - case 0: - return 0; - break; - case -ERROPEN: - ulogd_log(ULOGD_ERROR, - "unable to open configfile: %s\n", - ulogd_configfile); - break; - case -ERRMAND: - ulogd_log(ULOGD_ERROR, - "mandatory option \"%s\" not found\n", - config_errce->key); - break; - case -ERRMULT: - ulogd_log(ULOGD_ERROR, - "option \"%s\" occurred more than once\n", - config_errce->key); - break; - case -ERRUNKN: - ulogd_log(ULOGD_ERROR, - "unknown config key \"%s\"\n", - config_errce->key); - break; - case -ERRSECTION: - ulogd_log(ULOGD_ERROR, - "section \"%s\" not found\n", section); - break; - } - return 1; - -} - - -static struct config_keyset ulogd_kset = { - .num_ces = 4, - .ces = { - { - .key = "logfile", - .type = CONFIG_TYPE_STRING, - .options = CONFIG_OPT_NONE, - .u.string = ULOGD_LOGFILE_DEFAULT, - }, - { - .key = "plugin", - .type = CONFIG_TYPE_CALLBACK, - .options = CONFIG_OPT_MULTI, - .u.parser = &load_plugin, - }, - { - .key = "loglevel", - .type = CONFIG_TYPE_INT, - .options = CONFIG_OPT_NONE, - .u.value = 1, - }, - { - .key = "stack", - .type = CONFIG_TYPE_CALLBACK, - .options = CONFIG_OPT_NONE, - .u.parser = &create_stack, - }, - }, -}; - -#define logfile_ce ulogd_kset.ces[0] -#define plugin_ce ulogd_kset.ces[1] -#define loglevel_ce ulogd_kset.ces[2] -#define stack_ce ulogd_kset.ces[3] - - -static void deliver_signal_pluginstances(int signal) -{ - struct ulogd_pluginstance_stack *stack; - struct ulogd_pluginstance *pi; - - list_for_each_entry(stack, &ulogd_pi_stacks, stack_list) { - list_for_each_entry(pi, &stack->list, list) { - if (pi->plugin->signal) - (*pi->plugin->signal)(pi, signal); - } - } -} - -static void sigterm_handler(int signal) -{ - - ulogd_log(ULOGD_NOTICE, "sigterm received, exiting\n"); - - deliver_signal_pluginstances(signal); - - if (logfile != stdout) - fclose(logfile); - - exit(0); -} - -static void signal_handler(int signal) -{ - ulogd_log(ULOGD_NOTICE, "signal received, calling pluginstances\n"); - - deliver_signal_pluginstances(signal); - - /* reopen logfile */ - if (logfile != stdout) { - fclose(logfile); - logfile = fopen(logfile_ce.u.string, "a"); - if (!logfile) - sigterm_handler(signal); - } -} - -static void print_usage(void) -{ - /* FIXME */ - printf("ulogd Version %s\n", ULOGD_VERSION); - printf(COPYRIGHT); - printf("This is free software with ABSOLUTELY NO WARRANTY.\n\n"); - printf("Parameters:\n"); - printf("\t-h --help\tThis help page\n"); - printf("\t-V --version\tPrint version information\n"); - printf("\t-d --daemon\tDaemonize (fork into background)\n"); - printf("\t-c --configfile\tUse alternative Configfile\n"); - printf("\t-u --uid\tChange UID/GID\n"); -} - -static struct option opts[] = { - { "version", 0, NULL, 'V' }, - { "daemon", 0, NULL, 'd' }, - { "help", 0, NULL, 'h' }, - { "configfile", 1, NULL, 'c'}, - { "uid", 1, NULL, 'u' }, - { 0 } -}; - -int main(int argc, char* argv[]) -{ - int argch; - int daemonize = 0; - int change_uid = 0; - char *user = NULL; - struct passwd *pw; - uid_t uid = 0; - gid_t gid = 0; - - - while ((argch = getopt_long(argc, argv, "c:dh::Vu:", opts, NULL)) != -1) { - switch (argch) { - default: - case '?': - if (isprint(optopt)) - fprintf(stderr, "Unknown option `-%c'.\n", - optopt); - else - fprintf(stderr, "Unknown option character " - "`\\x%x'.\n", optopt); - - print_usage(); - exit(1); - break; - case 'h': - print_usage(); - exit(0); - break; - case 'd': - daemonize = 1; - break; - case 'V': - printf("ulogd Version %s\n", ULOGD_VERSION); - printf(COPYRIGHT); - exit(0); - break; - case 'c': - ulogd_configfile = optarg; - break; - case 'u': - change_uid = 1; - user = strdup(optarg); - pw = getpwnam(user); - if (!pw) { - printf("Unknown user %s.\n", user); - free(user); - exit(1); - } - uid = pw->pw_uid; - gid = pw->pw_gid; - break; - } - } - - if (config_register_file(ulogd_configfile)) { - ulogd_log(ULOGD_FATAL, "error registering configfile \"%s\"\n", - ulogd_configfile); - exit(1); - } - - /* parse config file */ - if (parse_conffile("global", &ulogd_kset)) { - ulogd_log(ULOGD_FATAL, "parse_conffile\n"); - exit(1); - } - - if (change_uid) { - ulogd_log(ULOGD_NOTICE, "Changing UID / GID\n"); - if (setgid(gid)) { - ulogd_log(ULOGD_FATAL, "can't set GID %u\n", gid); - ipulog_perror(NULL); - exit(1); - } - if (setegid(gid)) { - ulogd_log(ULOGD_FATAL, "can't sett effective GID %u\n", - gid); - ipulog_perror(NULL); - exit(1); - } - if (initgroups(user, gid)) { - ulogd_log(ULOGD_FATAL, "can't set user secondary GID\n"); - ipulog_perror(NULL); - exit(1); - } - if (setuid(uid)) { - ulogd_log(ULOGD_FATAL, "can't set UID %u\n", uid); - ipulog_perror(NULL); - exit(1); - } - if (seteuid(uid)) { - ulogd_log(ULOGD_FATAL, "can't set effective UID %u\n", - uid); - ipulog_perror(NULL); - exit(1); - } - } - - logfile_open(logfile_ce.u.string); - -#ifdef DEBUG - /* dump key and interpreter hash */ - interh_dump(); - keyh_dump(); -#endif - if (daemonize){ - if (fork()) { - exit(0); - } - if (logfile != stdout) - fclose(stdout); - fclose(stderr); - fclose(stdin); - setsid(); - } - - signal(SIGTERM, &sigterm_handler); - signal(SIGHUP, &signal_handler); - - ulogd_log(ULOGD_NOTICE, - "initialization finished, entering main loop\n"); - - ulogd_main_loop(); - - /* hackish, but result is the same */ - sigterm_handler(SIGTERM); - return(0); -} -- cgit v1.2.3