OSDN Git Service

Fix no pic
[uclinux-h8/uClinux-dist.git] / user / ulogd / ulogd.c
1 /* ulogd, Version $LastChangedRevision: 805 $
2  *
3  * $Id: ulogd.c 805 2005-04-18 14:39:10Z laforge $
4  *
5  * userspace logging daemon for the iptables ULOG target
6  * of the linux 2.4 netfilter subsystem.
7  *
8  * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License version 2 
12  *  as published by the Free Software Foundation
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, write to the Free Software
21  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  * $Id: ulogd.c 805 2005-04-18 14:39:10Z laforge $
24  *
25  * Modifications:
26  *      14 Jun 2001 Martin Josefsson <gandalf@wlug.westbo.se>
27  *              - added SIGHUP handler for logfile cycling
28  *
29  *      10 Feb 2002 Alessandro Bono <a.bono@libero.it>
30  *              - added support for non-fork mode
31  *              - added support for logging to stdout
32  *
33  *      09 Sep 2003 Magnus Boden <sarek@ozaba.cx>
34  *              - added support for more flexible multi-section conffile
35  *
36  *      20 Apr 2004 Nicolas Pougetoux <nicolas.pougetoux@edelweb.fr>
37  *              - added suppurt for seteuid()
38  */
39
40 #define ULOGD_VERSION   "1.23"
41
42 #include <unistd.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <stdarg.h>
47 #include <time.h>
48 #include <ctype.h>
49 #include <signal.h>
50 #include <dlfcn.h>
51 #include <sys/types.h>
52 #include <dirent.h>
53 #include <getopt.h>
54 #include <pwd.h>
55 #include <grp.h>
56 #include <syslog.h>
57 #include <libipulog/libipulog.h>
58 #include <ulogd/conffile.h>
59 #include <ulogd/ulogd.h>
60
61 /* Size of the socket recevive memory.  Should be at least the same size as the
62  * 'nlbufsiz' module loadtime parameter of ipt_ULOG.o
63  * If you have _big_ in-kernel queues, you may have to increase this number.  (
64  * --qthreshold 100 * 1500 bytes/packet = 150kB  */
65 #define ULOGD_RMEM_DEFAULT      131071
66
67 /* Size of the receive buffer for the netlink socket.  Should be at least of
68  * RMEM_DEFAULT size.  */
69 #define ULOGD_BUFSIZE_DEFAULT   150000
70
71 #ifdef DEBUG
72 #define DEBUGP(format, args...) fprintf(stderr, format, ## args)
73 #else
74 #define DEBUGP(format, args...) 
75 #endif
76
77 /* default config parameters, if not changed in configfile */
78 #ifndef ULOGD_LOGFILE_DEFAULT
79 #define ULOGD_LOGFILE_DEFAULT   "/var/log/ulogd.log"
80 #endif
81 #ifndef ULOGD_NLGROUP_DEFAULT
82 #define ULOGD_NLGROUP_DEFAULT   32
83 #endif
84
85 /* where to look for the config file */
86 #ifndef ULOGD_CONFIGFILE
87 #define ULOGD_CONFIGFILE        "/etc/ulogd.conf"
88 #endif
89
90 /* global variables */
91 static struct ipulog_handle *libulog_h; /* our libipulog handle */
92 static unsigned char* libulog_buf;      /* the receive buffer */
93 static int loglevel = 1;                /* current loglevel */
94 static char *ulogd_configfile = ULOGD_CONFIGFILE;
95
96 FILE *logfile = NULL;                   /* logfile pointer */
97
98 /* linked list for all registered interpreters */
99 static ulog_interpreter_t *ulogd_interpreters;
100
101 /* linked list for all registered output targets */
102 static ulog_output_t *ulogd_outputs;
103
104 /***********************************************************************
105  * INTERPRETER AND KEY HASH FUNCTIONS                   (new in 0.9)
106  ***********************************************************************/
107
108 /* We keep hashtables of interpreters and registered keys. The hash-tables
109  * are allocated dynamically at program load time. You may control the
110  * allocation granularity of both hashes (i.e. the amount of hashtable
111  * entries are allocated at one time) through modification of the constants
112  * INTERH_ALLOC_GRAN and KEYH_ALLOC_GRAN 
113  */
114
115 /* allocation granularith */
116 #define INTERH_ALLOC_GRAN       5
117
118 /* hashtable for all registered interpreters */
119 static ulog_interpreter_t **ulogd_interh;
120
121 /* current hashtable size */
122 static unsigned int ulogd_interh_ids_alloc;
123
124 /* total number of registered ids */
125 static unsigned int ulogd_interh_ids;
126
127 /* allocate a new interpreter id and write it into the interpreter struct */
128 static unsigned int interh_allocid(ulog_interpreter_t *ip)
129 {
130         unsigned int id;
131
132         id = ++ulogd_interh_ids;
133         
134         if (id >= ulogd_interh_ids_alloc) {
135                 if (!ulogd_interh)
136                         ulogd_interh = (ulog_interpreter_t **) 
137                                 malloc(INTERH_ALLOC_GRAN *
138                                         sizeof(ulog_interpreter_t));
139                 else
140                         ulogd_interh = (ulog_interpreter_t **)
141                                 realloc(ulogd_interh, 
142                                         (INTERH_ALLOC_GRAN +
143                                          ulogd_interh_ids_alloc) *
144                                         sizeof(ulog_interpreter_t));
145
146                 ulogd_interh_ids_alloc += INTERH_ALLOC_GRAN;
147         }
148
149         ip->id = id;
150         ulogd_interh[id] = ip;
151         return id;
152 }
153
154 /* get interpreter id by name */
155 unsigned int interh_getid(const char *name)
156 {
157         unsigned int i;
158         for (i = 1; i <= ulogd_interh_ids; i++)
159                 if (!strcmp(name, (ulogd_interh[i])->name))
160                         return i;
161
162         return 0;
163 }
164
165 #ifdef DEBUG
166 /* dump out the contents of the interpreter hash */
167 static void interh_dump(void)
168 {
169         unsigned int i;
170
171         for (i = 1; i <= ulogd_interh_ids; i++)
172                 ulogd_log(ULOGD_DEBUG, "ulogd_interh[%d] = %s\n", 
173                         i, (ulogd_interh[i])->name);
174
175 }
176 #endif
177
178 /* key hash allocation granularity */
179 #define KEYH_ALLOC_GRAN 20
180
181 /* hash table for key ids */
182 struct ulogd_keyh_entry *ulogd_keyh;
183
184 /* current size of the hashtable */
185 static unsigned int ulogd_keyh_ids_alloc;
186
187 /* total number of registered keys */
188 static unsigned int ulogd_keyh_ids;
189
190 /* allocate a new key_id */
191 static unsigned int keyh_allocid(ulog_interpreter_t *ip, unsigned int offset,
192                                 const char *name)
193 {
194         unsigned int id;
195
196         id = ++ulogd_keyh_ids;
197
198         if (id >= ulogd_keyh_ids_alloc) {
199                 if (!ulogd_keyh) {
200                         ulogd_keyh = (struct ulogd_keyh_entry *)
201                                 malloc(KEYH_ALLOC_GRAN * 
202                                         sizeof(struct ulogd_keyh_entry));
203                         if (!ulogd_keyh) {
204                                 ulogd_log(ULOGD_ERROR, "OOM!\n");
205                                 return 0;
206                         }
207                 } else {
208                         ulogd_keyh = (struct ulogd_keyh_entry *)
209                                 realloc(ulogd_keyh, (KEYH_ALLOC_GRAN
210                                                 +ulogd_keyh_ids_alloc) *
211                                         sizeof(struct ulogd_keyh_entry));
212
213                         if (!ulogd_keyh) {
214                                 ulogd_log(ULOGD_ERROR, "OOM!\n");
215                                 return 0;
216                         }
217                 }
218
219                 ulogd_keyh_ids_alloc += KEYH_ALLOC_GRAN;
220         }
221
222         ulogd_keyh[id].interp = ip;
223         ulogd_keyh[id].offset = offset;
224         ulogd_keyh[id].name = name;
225
226         return id;
227 }
228
229 #ifdef DEBUG
230 /* dump the keyhash to standard output */
231 static void keyh_dump(void)
232 {
233         unsigned int i;
234
235         printf("dumping keyh\n");
236         for (i = 1; i <= ulogd_keyh_ids; i++)
237                 printf("ulogd_keyh[%lu] = %s:%u\n", i, 
238                         ulogd_keyh[i].interp->name, ulogd_keyh[i].offset);
239 }
240 #endif
241
242 /* get keyid by name */
243 unsigned int keyh_getid(const char *name)
244 {
245         unsigned int i;
246         for (i = 1; i <= ulogd_keyh_ids; i++)
247                 if (!strcmp(name, ulogd_keyh[i].name))
248                         return i;
249
250         return 0;
251 }
252
253 /* get key name by keyid */
254 char *keyh_getname(unsigned int id)
255 {
256         if (id > ulogd_keyh_ids) {
257                 ulogd_log(ULOGD_NOTICE, 
258                         "keyh_getname called with invalid id%u\n", id);
259                 return NULL;
260         }
261                 
262         return ulogd_keyh[id].interp->name;
263 }
264
265 /* get result for given key id. does not check if result valid */
266 ulog_iret_t *keyh_getres(unsigned int id)
267 {
268         ulog_iret_t *ret;
269
270         if (id > ulogd_keyh_ids) {
271                 ulogd_log(ULOGD_NOTICE,
272                         "keyh_getres called with invalid id %d\n", id);
273                 return NULL;
274         }
275
276         ret = &ulogd_keyh[id].interp->result[ulogd_keyh[id].offset];
277
278         return ret;
279 }
280
281 /***********************************************************************
282  * INTERPRETER MANAGEMENT 
283  ***********************************************************************/
284
285 /* try to lookup a registered interpreter for a given name */
286 static ulog_interpreter_t *find_interpreter(const char *name)
287 {
288         unsigned int id;
289         
290         id = interh_getid(name);
291         if (!id)
292                 return NULL;
293
294         return ulogd_interh[id];
295 }
296
297 /* the function called by all interpreter plugins for registering their
298  * target. */ 
299 void register_interpreter(ulog_interpreter_t *me)
300 {
301         unsigned int i;
302
303         /* check if we already have an interpreter with this name */
304         if (find_interpreter(me->name)) {
305                 ulogd_log(ULOGD_NOTICE, 
306                         "interpreter `%s' already registered\n", me->name);
307                 return;
308         }
309
310         ulogd_log(ULOGD_INFO, "registering interpreter `%s'\n", me->name);
311
312         /* allocate a new interpreter id for it */
313         if (!interh_allocid(me)) {
314                 ulogd_log(ULOGD_ERROR, "unable to obtain interh_id for "
315                         "interpreter '%s'\n", me->name);
316                 return;
317         }
318
319         /* - allocate one keyh_id for each result of this interpreter 
320          * - link the elements to each other */
321         for (i = 0; i < me->key_num; i++) {
322                 if (!keyh_allocid(me, i, me->result[i].key)) {
323                         ulogd_log(ULOGD_ERROR, "unable to obtain keyh_id "
324                                 "for interpreter %s, key %d", me->name,
325                                 me->result[i].key);
326                         continue;
327                 }
328                 if (i != me->key_num - 1)
329                         me->result[i].next = &me->result[i+1];
330         }
331
332         /* all work done, we can prepend the new interpreter to the list */
333         if (ulogd_interpreters)
334                 me->result[me->key_num - 1].next = 
335                                         &ulogd_interpreters->result[0];
336         me->next = ulogd_interpreters;
337         ulogd_interpreters = me;
338 }
339
340 /***********************************************************************
341  * OUTPUT MANAGEMENT 
342  ***********************************************************************/
343
344 /* try to lookup a registered output plugin for a given name */
345 static ulog_output_t *find_output(const char *name)
346 {
347         ulog_output_t *ptr;
348
349         for (ptr = ulogd_outputs; ptr; ptr = ptr->next) {
350                 if (strcmp(name, ptr->name) == 0)
351                                 return ptr;
352         }
353
354         return NULL;
355 }
356
357 /* the function called by all output plugins for registering themselves */
358 void register_output(ulog_output_t *me)
359 {
360         if (find_output(me->name)) {
361                 ulogd_log(ULOGD_NOTICE, "output `%s' already registered\n",
362                                 me->name);
363                 exit(EXIT_FAILURE);
364         }
365         ulogd_log(ULOGD_NOTICE, "registering output `%s'\n", me->name);
366         me->next = ulogd_outputs;
367         ulogd_outputs = me;
368 }
369
370 /***********************************************************************
371  * MAIN PROGRAM
372  ***********************************************************************/
373
374 static FILE syslog_dummy;
375
376 static inline int ulogd2syslog_level(int level)
377 {
378         int syslog_level = LOG_WARNING;
379
380         switch (level) {
381                 case ULOGD_DEBUG:
382                         syslog_level = LOG_DEBUG;
383                         break;
384                 case ULOGD_INFO:
385                         syslog_level = LOG_INFO;
386                         break;
387                 case ULOGD_NOTICE:
388                         syslog_level = LOG_NOTICE;
389                         break;
390                 case ULOGD_ERROR:
391                         syslog_level = LOG_ERR;
392                         break;
393                 case ULOGD_FATAL:
394                         syslog_level = LOG_CRIT;
395                         break;
396         }
397         return syslog_level;
398 }
399
400 /* log message to the logfile */
401 void __ulogd_log(int level, char *file, int line, const char *format, ...)
402 {
403         char *timestr;
404         va_list ap;
405         time_t tm;
406         FILE *outfd;
407
408         /* log only messages which have level at least as high as loglevel */
409         if (level < loglevel)
410                 return;
411
412         if (logfile == &syslog_dummy) {
413                 /* FIXME: this omit's the 'file' string */
414                 va_start(ap, format);
415                 vsyslog(ulogd2syslog_level(level), format, ap);
416                 va_end(ap);
417         } else {
418                 if (logfile)
419                         outfd = logfile;
420                 else
421                         outfd = stderr;
422
423                 va_start(ap, format);
424
425                 tm = time(NULL);
426                 timestr = ctime(&tm);
427                 timestr[strlen(timestr)-1] = '\0';
428                 fprintf(outfd, "%s <%1.1d> %s:%d ", timestr, level, file, line);
429                 
430                 vfprintf(outfd, format, ap);
431                 va_end(ap);
432
433                 /* flush glibc's buffer */
434                 fflush(outfd);
435         }
436 }
437
438 /* propagate results to all registered output plugins */
439 static void propagate_results(ulog_iret_t *ret)
440 {
441         ulog_output_t *p;
442
443         for (p = ulogd_outputs; p; p = p->next) {
444                 (*p->output)(ret);
445         }
446 }
447
448 /* clean results (set all values to 0 and free pointers) */
449 static void clean_results(ulog_iret_t *ret)
450 {
451         ulog_iret_t *r;
452
453         for (r = ret; r; r = r->next) {
454                 if (r->flags & ULOGD_RETF_FREE) {
455                         free(r->value.ptr);
456                         r->value.ptr = NULL;
457                 }
458                 memset(&r->value, 0, sizeof(r->value));
459                 r->flags &= ~ULOGD_RETF_VALID;
460         }
461 }
462
463 /* call all registered interpreters and hand the results over to 
464  * propagate_results */
465 static void handle_packet(ulog_packet_msg_t *pkt)
466 {
467         ulog_iret_t *ret;
468         ulog_iret_t *allret = NULL;
469         ulog_interpreter_t *ip;
470
471         unsigned int i,j;
472
473         /* If there are no interpreters registered yet,
474          * ignore this packet */
475         if (!ulogd_interh_ids) {
476                 ulogd_log(ULOGD_NOTICE, 
477                           "packet received, but no interpreters found\n");
478                 return;
479         }
480
481         for (i = 1; i <= ulogd_interh_ids; i++) {
482                 ip = ulogd_interh[i];
483                 /* call interpreter */
484                 if ((ret = ((ip)->interp)(ip, pkt))) {
485                         /* create references for result linked-list */
486                         for (j = 0; j < ip->key_num; j++) {
487                                 if (IS_VALID(ip->result[j])) {
488                                         ip->result[j].cur_next = allret;
489                                         allret = &ip->result[j];
490                                 }
491                         }
492                 }
493         }
494         propagate_results(allret);
495         clean_results(ulogd_interpreters->result);
496 }
497
498 /* plugin loader to dlopen() a plugins */
499 static int load_plugin(char *file)
500 {
501         if (!dlopen(file, RTLD_NOW)) {
502                 ulogd_log(ULOGD_ERROR, "load_plugins: '%s': %s\n", file,
503                           dlerror());
504                 return 1;
505         }
506         return 0;
507 }
508
509 /* open the logfile */
510 static int logfile_open(const char *name)
511 {
512         if (!strcmp(name, "syslog")) {
513                 openlog("ulogd", LOG_PID, LOG_DAEMON);
514                 logfile = &syslog_dummy;
515         } else if (!strcmp(name,"stdout"))
516                 logfile = stdout;
517         else {
518                 logfile = fopen(name, "a");
519                 if (!logfile) {
520                         fprintf(stderr, "ERROR: can't open logfile %s: %s\n", 
521                                 name, strerror(errno));
522                         exit(2);
523                 }
524         }
525         ulogd_log(ULOGD_INFO, "ulogd Version %s starting\n", ULOGD_VERSION);
526         return 0;
527 }
528
529 /* wrapper to handle conffile error codes */
530 static int parse_conffile(const char *section, config_entry_t *ce)
531 {
532         int err;
533
534         err = config_parse_file(section, ce);
535
536         switch(err) {
537                 case 0:
538                         return 0;
539                         break;
540                 case -ERROPEN:
541                         ulogd_log(ULOGD_ERROR,
542                                 "unable to open configfile: %s\n",
543                                 ulogd_configfile);
544                         break;
545                 case -ERRMAND:
546                         ulogd_log(ULOGD_ERROR,
547                                 "mandatory option \"%s\" not found\n",
548                                 config_errce->key);
549                         break;
550                 case -ERRMULT:
551                         ulogd_log(ULOGD_ERROR,
552                                 "option \"%s\" occurred more than once\n",
553                                 config_errce->key);
554                         break;
555                 case -ERRUNKN:
556                         ulogd_log(ULOGD_ERROR,
557                                 "unknown config key \"%s\"\n",
558                                 config_errce->key);
559                         break;
560                 case -ERRSECTION:
561                         ulogd_log(ULOGD_ERROR,
562                                 "section \"%s\" not found\n", section);
563                         break;
564         }
565         return 1;
566
567 }
568
569 /* configuration directives of the main program */
570 static config_entry_t logf_ce = { NULL, "logfile", CONFIG_TYPE_STRING, 
571                                   CONFIG_OPT_NONE, 0, 
572                                   { string: ULOGD_LOGFILE_DEFAULT } };
573
574 static config_entry_t bufsiz_ce = { &logf_ce, "bufsize", CONFIG_TYPE_INT,       
575                                    CONFIG_OPT_NONE, 0,
576                                    { value: ULOGD_BUFSIZE_DEFAULT } }; 
577
578 static config_entry_t plugin_ce = { &bufsiz_ce, "plugin", CONFIG_TYPE_CALLBACK,
579                                     CONFIG_OPT_MULTI, 0, 
580                                     { parser: &load_plugin } };
581
582 static config_entry_t nlgroup_ce = { &plugin_ce, "nlgroup", CONFIG_TYPE_INT,
583                                      CONFIG_OPT_NONE, 0,
584                                      { value: ULOGD_NLGROUP_DEFAULT } };
585
586 static config_entry_t loglevel_ce = { &nlgroup_ce, "loglevel", CONFIG_TYPE_INT,
587                                       CONFIG_OPT_NONE, 0, 
588                                       { value: 1 } };
589 static config_entry_t rmem_ce = { &loglevel_ce, "rmem", CONFIG_TYPE_INT,
590                                   CONFIG_OPT_NONE, 0, 
591                                   { value: ULOGD_RMEM_DEFAULT } };
592
593 static void sigterm_handler(int signal)
594 {
595         ulog_output_t *p;
596         
597         ulogd_log(ULOGD_NOTICE, "sigterm received, exiting\n");
598
599         ipulog_destroy_handle(libulog_h);
600         free(libulog_buf);
601         if (logfile != stdout && logfile != &syslog_dummy)
602                 fclose(logfile);
603
604         for (p = ulogd_outputs; p; p = p->next) {
605                 if (p->fini)
606                         (*p->fini)();
607         }
608
609         exit(0);
610 }
611
612 static void sighup_handler(int signal)
613 {
614         ulog_output_t *p;
615
616         if (logfile != stdout && logfile != &syslog_dummy) {
617                 fclose(logfile);
618                 logfile = fopen(logf_ce.u.string, "a");
619                 if (!logfile)
620                         sigterm_handler(signal);
621         }
622
623         ulogd_log(ULOGD_NOTICE, "sighup received, calling plugin handlers\n");
624         
625         for (p = ulogd_outputs; p; p = p->next) {
626                 if (p->signal)
627                         (*p->signal)(SIGHUP);
628         }
629 }
630
631 static void print_usage(void)
632 {
633         /* FIXME */
634         printf("ulogd Version %s\n", ULOGD_VERSION);
635         printf("Copyright (C) 2000-2005 Harald Welte "
636                "<laforge@gnumonks.org>\n");
637         printf("This is free software with ABSOLUTELY NO WARRANTY.\n\n");
638         printf("Parameters:\n");
639         printf("\t-h --help\tThis help page\n");
640         printf("\t-V --version\tPrint version information\n");
641         printf("\t-d --daemon\tDaemonize (fork into background)\n");
642         printf("\t-c --configfile\tUse alternative Configfile\n");
643         printf("\t-u --uid\tChange UID/GID\n");
644 }
645
646 static struct option opts[] = {
647         { "version", 0, NULL, 'V' },
648         { "daemon", 0, NULL, 'd' },
649         { "help", 0, NULL, 'h' },
650         { "configfile", 1, NULL, 'c'},
651         { "uid", 1, NULL, 'u' },
652         { 0 }
653 };
654
655 int main(int argc, char* argv[])
656 {
657         int len;
658         int argch;
659         int daemonize = 0;
660         int change_uid = 0;
661         char *user = NULL;
662         struct passwd *pw;
663         uid_t uid = 0;
664         gid_t gid = 0;
665         ulog_packet_msg_t *upkt;
666         ulog_output_t *p;
667
668
669         while ((argch = getopt_long(argc, argv, "c:dh::Vu:", opts, NULL)) != -1) {
670                 switch (argch) {
671                 default:
672                 case '?':
673                         if (isprint(optopt))
674                                 fprintf(stderr, "Unknown option `-%c'.\n", optopt);
675                         else
676                                 fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
677
678                         print_usage();
679                         exit(1);
680                         break;
681                 case 'h':
682                         print_usage();
683                         exit(0);
684                         break;
685                 case 'd':
686                         daemonize = 1;
687                         break;
688                 case 'V':
689                         printf("ulogd Version %s\n", ULOGD_VERSION);
690                         printf("Copyright (C) 2000-2005 Harald Welte "
691                                "<laforge@gnumonks.org>\n");
692                         exit(0);
693                         break;
694                 case 'c':
695                         ulogd_configfile = optarg;
696                         break;
697                 case 'u':
698                         change_uid = 1;
699                         user = strdup(optarg);
700                         pw = getpwnam(user);
701                         if (!pw) {
702                                 printf("Unknown user %s.\n", user);
703                                 free(user);
704                                 exit(1);
705                         }
706                         uid = pw->pw_uid;
707                         gid = pw->pw_gid;
708                         break;
709                 }
710         }
711
712         if (config_register_file(ulogd_configfile)) {
713                 ulogd_log(ULOGD_FATAL, "error registering configfile \"%s\"\n",
714                           ulogd_configfile);
715                 exit(1);
716         }
717         
718         /* parse config file */
719         if (parse_conffile("global", &rmem_ce)) {
720                 ulogd_log(ULOGD_FATAL, "parse_conffile\n");
721                 exit(1);
722         }
723
724         /* allocate a receive buffer */
725         libulog_buf = (unsigned char *) malloc(bufsiz_ce.u.value);
726
727         if (!libulog_buf) {
728                 ulogd_log(ULOGD_FATAL, "unable to allocate receive buffer"
729                           "of %d bytes\n", bufsiz_ce.u.value);
730                 ipulog_perror(NULL);
731                 exit(1);
732         }
733
734         /* create ipulog handle */
735         libulog_h = ipulog_create_handle(ipulog_group2gmask(nlgroup_ce.u.value),
736                                          rmem_ce.u.value);
737
738         if (!libulog_h) {
739                 /* if some error occurrs, print it to stderr */
740                 ulogd_log(ULOGD_FATAL, "unable to create ipulogd handle\n");
741                 ipulog_perror(NULL);
742                 exit(1);
743         }
744
745
746         if (change_uid) {
747                 ulogd_log(ULOGD_NOTICE, "Changing UID / GID\n");
748                 if (setgid(gid)) {
749                         ulogd_log(ULOGD_FATAL, "can't set GID\n");
750                         ipulog_perror(NULL);
751                         exit(1);
752                 }
753                 if (setegid(gid)) {
754                         ulogd_log(ULOGD_FATAL, "can't sett effective GID\n");
755                         ipulog_perror(NULL);
756                         exit(1);
757                 }
758                 if (initgroups(user, gid)) {
759                         ulogd_log(ULOGD_FATAL, "can't set user secondary GID\n");
760                         ipulog_perror(NULL);
761                         exit(1);
762                 }
763                 if (setuid(uid)) {
764                         ulogd_log(ULOGD_FATAL, "can't set UID\n");
765                         ipulog_perror(NULL);
766                         exit(1);
767                 }
768                 if (seteuid(uid)) {
769                         ulogd_log(ULOGD_FATAL, "can't set effective UID\n");
770                         ipulog_perror(NULL);
771                         exit(1);
772                 }
773         }
774
775         logfile_open(logf_ce.u.string);
776
777         for (p = ulogd_outputs; p; p = p->next) {
778                 if (p->init)
779                         (*p->init)();
780         }
781
782 #ifdef DEBUG
783         /* dump key and interpreter hash */
784         interh_dump();
785         keyh_dump();
786 #endif
787         if (daemonize){
788                 if (fork()) {
789                         exit(0);
790                 }
791                 if (logfile != stdout)
792                         fclose(stdout);
793                 fclose(stderr);
794                 fclose(stdin);
795                 setsid();
796         }
797
798         /* send SIGINT to the term handler, since they hit CTRL-C */
799         signal(SIGINT, &sigterm_handler);
800         signal(SIGHUP, &sighup_handler);
801         signal(SIGTERM, &sigterm_handler);
802
803         ulogd_log(ULOGD_NOTICE, 
804                   "initialization finished, entering main loop\n");
805
806         /* endless loop receiving packets and handling them over to
807          * handle_packet */
808         while ((len = ipulog_read(libulog_h, libulog_buf, 
809                                  bufsiz_ce.u.value, 1))) {
810
811                 if (len <= 0) {
812                         /* this is not supposed to happen */
813                         ulogd_log(ULOGD_ERROR, "ipulog_read == %d! "
814                                   "ipulog_errno == %d, errno = %d\n",
815                                   len, ipulog_errno, errno);
816                 } else {
817                         while ((upkt = ipulog_get_packet(libulog_h,
818                                                libulog_buf, len))) {
819                                 DEBUGP("==> packet received\n");
820                                 handle_packet(upkt);
821                         }
822                 }
823         }
824
825         /* hackish, but result is the same */
826         sigterm_handler(SIGTERM);       
827         return(0);
828 }