📄 conf.c
字号:
/* * This file is part of Firestorm NIDS * Copyright (c) 2002 Gianni Tedesco * This program is released under the terms of the GNU GPL version 2 * * This file reads in the configuration file and sets up all of * the enviroment for the firestorm NIDS sensor to run. Default * settings try to be as secure as possible, we are quite strict * if you want to configure firestorm in an obviously insecure * way, you can recompile with checks removed. * * TODO * o preserve filename/line number for error messages */#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <fcntl.h>#include <string.h>#include <ctype.h>#include <firestorm.h>#include <args.h>#include <cleanup.h>#include <loader.h>#include <packet.h>#include <alert.h>#include <signature.h>#include <preproc.h>#include <decode.h>#include <capture.h>#include <target.h>#include <matcher.h>#include <parser.h>#include <conf.h>#ifndef _BSD_SOURCE#define _BSD_SOURCE#endif#include <grp.h>/* limited by AVAL_SIZE in most cases anyway */#define CONF_MAXLEN 1024struct conf { struct conf *next; char *data;};struct conf *cnf_plugins=NULL, *cnf_plugins_tail=NULL;struct conf *cnf_plugin=NULL, *cnf_plugin_tail=NULL;struct conf *cnf_preproc=NULL, *cnf_preproc_tail=NULL;struct conf *cnf_sig=NULL, *cnf_sig_tail=NULL;unsigned int f_uid=0;unsigned int f_gid=0;unsigned int do_chroot=1;char *root_dir=NULL;char *output_line=NULL;char *cap_line=NULL;char *logfile=NULL;/* Callbacks that can only be called once */int conf_rootfn(struct arg *a, void *u){ if ( root_dir ) return 0; return ( (root_dir=strdup(a->val.v_str))!=NULL );}int conf_outputfn(struct arg *a, void *u){ if ( output_line ) return 0; return ( (output_line=strdup(a->val.v_str))!=NULL );}int conf_capfn(struct arg *a, void *u){ if ( cap_line ) return 0; return ( (cap_line=strdup(a->val.v_str))!=NULL );}int conf_logfile(struct arg *a, void *u){ if ( logfile ) return 0; return ( (logfile=strdup(a->val.v_str))!=NULL );}/* Add a line to a list of lines */int conf_addline(struct conf **head, struct conf **tail, char *str){ struct conf *c; if ( !(c=calloc(1, sizeof(*c))) ) cperror("calloc"); if ( !(c->data=strdup(str)) ) cperror("strdup"); if ( !(*head) ) { (*head)=c; (*tail)=c; }else{ (*tail)->next=c; (*tail)=c; } return 1;}/* Callbacks that can be called multiple times */int conf_plugins(struct arg *a, void *u){ return conf_addline(&cnf_plugins, &cnf_plugins_tail, a->val.v_str);}int conf_plugin(struct arg *a, void *u){ return conf_addline(&cnf_plugin, &cnf_plugin_tail, a->val.v_str);}int conf_preproc(struct arg *a, void *u){ return conf_addline(&cnf_preproc, &cnf_preproc_tail, a->val.v_str);}int conf_sig(struct arg *a, void *u){ return conf_addline(&cnf_sig, &cnf_sig_tail, a->val.v_str);}struct arg firestorm_args[]={ {"effective_uid", ARGTYPE_PUINT, NULL, {.vp_uint=&f_uid}}, {"effective_gid", ARGTYPE_PUINT, NULL, {.vp_uint=&f_gid}}, {"chroot", ARGTYPE_PBOOL, NULL, {.vp_bool=&do_chroot}}, {"firestorm_root", ARGTYPE_STRING, conf_rootfn}, {"capture", ARGTYPE_STRING, conf_capfn}, {"output", ARGTYPE_STRING, conf_outputfn}, {"logfile", ARGTYPE_STRING, conf_logfile}, {"load_plugins", ARGTYPE_STRING, conf_plugins}, {"load_plugin", ARGTYPE_STRING, conf_plugin}, {"preprocessor", ARGTYPE_STRING, conf_preproc}, {"signatures", ARGTYPE_STRING, conf_sig}, {NULL,ARGTYPE_NOP,NULL}};/* Perform initial file descriptor tweaks */void conf_tweak_fds(){ int fds=sysconf(_SC_OPEN_MAX); while(fds>2) close(fds--); if ( (fds=open("/dev/null", O_RDWR))<0 ) { cleanup(EXIT_ERR, "/dev/null: open(): %s", get_err()); } /* Make stdin and stderr be /dev/null */ if ( fds!=0 && dup2(fds,0)<0 ) cleanup(EXIT_ERR, "stdin: dup2(): %s", get_err()); if ( fds!=2 && dup2(fds,2)<0 ) cleanup(EXIT_ERR, "stderr: dup2(): %s", get_err()); if ( fds>2 ) close(fds);}/* Open the config file, we need to do some funky stuff */FILE *conf_open(char *fn){ int fd; FILE *ret; if ( (fd=open(fn, O_RDONLY))<0 ) { cleanup(EXIT_ERR, "%s: open(): %s", fn, get_err()); } /* If we were opened with stdout closed the config * could end up as fd1, that kinda sucks because when * we close it, some other bit of code may open fd1 as * writable! printing to stdout would then corrupt the * file - I know we are never setuid but better to be safe */ if ( fd==1 ) { /* We know fd3 is closed already */ if ( dup2(fd, 3)<0 ) cleanup(EXIT_ERR, "%s: dup2(): %s", fn, get_err()); /* We know stdin is /dev/null, make it stdout too */ if ( dup2(0, 1)<0 ) cleanup(EXIT_ERR, "stdout: dup2(): %s", get_err()); } /* Open for stdio */ if ( !(ret=fdopen(fd, "r")) ) { cleanup(EXIT_ERR, "%s: fdopen(): %s", fn, get_err()); } return ret;}/* Go in to the background (properly damnit) */void conf_background(void){ switch(fork()) { case 0: break; case -1: cleanup(EXIT_ERR, "fork(): %s", get_err()); default: _exit(0); } /* This is so that we can't re-aquire a controlling terminal */ if (setsid()<0) { cleanup(EXIT_ERR, "setsid(): %s", get_err()); } switch(fork()) { case 0: break; case -1: cleanup(EXIT_ERR, "fork(): %s", get_err()); default: _exit(0); }}/* Parse a line */int conf_line(char *buf, char *fn, int line){ char *cur; int state=0; char *val=NULL; for(cur=buf; *cur!=0 && *cur!='\r' && *cur!='\n'; cur++) { switch(state) { case 2: continue; case 0: if ( isspace(*cur) ) { state=1; *cur=0; } break; case 1: if ( !isspace(*cur) ) { val=cur; state=2; } break; } } if ( *cur==0 ) { cleanup(EXIT_ERR, "%s:%i: line limit is %u characters", fn, line, CONF_MAXLEN); }else *cur=0; if ( arg_found(firestorm_args, buf, strlen(buf), val, strlen(val), NULL)<=0 ) { return -1; } return 0;}/* Parse the whole file */void conf_read(char *fn, FILE *f){ char buf[CONF_MAXLEN]; int line=0; while(fgets(buf, sizeof(buf), f)) { char *p=buf; line++; while( *p && isspace(*p) ) p++; if ( *p==0 || *p=='#' ) continue; if ( conf_line(buf, fn, line) ) { fclose(f); cleanup(EXIT_ERR, "%s:%i: parse error", fn, line); } } fclose(f); return;}/* Split a string in two by whitespace */char *conf_split_once(char *l){ int state=0; char *a; for(a=l; *a; a++) { switch (state) { case 0: if ( isspace(*a) ) { *a=0; state=1; } break; case 1: if ( !isspace(*a) ) goto done; break; } }done: return a;}/* parse a preproc line and add it */void conf_do_preproc(char *d){ char *a; a=conf_split_once(d); if ( !preproc_setup(d, a) ) { cleanup(EXIT_ERR, "cannot find preproc: %s", d); }}/* parse a signature line and add it */void conf_do_sig(char *d){ char *a; a=conf_split_once(d); if ( !parser_setup(d, a) ) { cleanup(EXIT_ERR, "%s: error loading %s signatures", a, d); }}/* parse the capture line, and set it all up */void conf_capture(void){ char *a; a=conf_split_once(cap_line); /* this will call cleanup() if it fails */ capture_setup(cap_line, a); free(cap_line);}/* Perform firestorm sensor configuration */void conf_go(char *fn){ struct conf *c; uid_t init_uid=geteuid(); /* cant fail */ /* If you want to do something this stupid then you * will have to recompile the code - i wont help you */ if ( init_uid != getuid() ) cleanup(EXIT_ERR, "SUID is for dumb ass motherfuckers"); conf_tweak_fds(); conf_read(fn, conf_open(fn)); /* Check there actually was even a capture line in the config */ if ( !cap_line ) cleanup(EXIT_ERR, "no captures specified!"); /* Change to root directory */ if ( root_dir ) { if ( chdir(root_dir) ) cleanup(EXIT_ERR, "%s: chdir(): %s", root_dir, get_err()); free(root_dir); }else{ /* by default change to root, that way firestorm * wont stop the administrator unmounting whatever * filesystem we were run inside of */ if ( chdir("/") ) cleanup(EXIT_ERR, "/: chdir(): %s", get_err()); } /* load plugins from directories */ while(cnf_plugins) { c=cnf_plugins; cnf_plugins=c->next; loader_load_dir(c->data); free(c->data); free(c); } /* load individual plugin files */ while(cnf_plugin) { c=cnf_plugin; cnf_plugin=c->next; if ( !loader_load(c->data) ) { cleanup(EXIT_ERR, "unable to load a plugin", c->data); } free(c->data); free(c); } /* Load in the actual objects that we want */ decode_load(); capdev_load(); matcher_load(); preproc_load(); parser_load(); /* chroot (properly damnit) */ if ( do_chroot && init_uid ) { mesg(M_WARN, "cannot chroot, no privileges"); }else if ( do_chroot && chroot(".") ) { cleanup(EXIT_ERR, "chroot(): %s", get_err()); } /* Initialise capture */ conf_capture(); /* Drop privileges (properly damnit) */ if ( !init_uid ) { if ( !f_gid || !f_uid ) cleanup(EXIT_ERR, "running as root is seriously stupid"); if ( setgroups(1,&f_gid) || setgid(f_gid) ) { cleanup(EXIT_ERR, "unable to drop gid to %u: %s", f_gid, get_err()); } if ( setuid(f_uid) ) { cleanup(EXIT_ERR, "unable to drop uid to %u: %s", f_uid, get_err()); } } /* open alert output file */ if ( !output_line ) cleanup(EXIT_ERR, "no output options specified"); alert_conf_hook(output_line); free(output_line); /* initialise preprocessors */ while(cnf_preproc) { c=cnf_preproc; cnf_preproc=c->next; conf_do_preproc(c->data); free(c->data); free(c); } /* load signatures */ while(cnf_sig) { c=cnf_sig; cnf_sig=c->next; conf_do_sig(c->data); free(c->data); free(c); } /* sort out mesg() output */ mesg_logfile(logfile); if ( logfile ) { /* Daemonize (properly damnit) */ conf_background(); } /* Actually open alert log etc.. */ alert_conf_go();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -