Example #1
0
int main(int argc, char **argv)
{

    const struct option long_options[] =
    {
        { "help",         no_argument,          NULL,   'h' },
        { "debug",        required_argument,    NULL,   'd' },
        { "daemon",       no_argument,          NULL,   'D' },
        { "user",         required_argument,    NULL,   'u' },
        { "chroot",       required_argument,    NULL,   'c' },
        { "credits",	  no_argument,		NULL,	'C' },
        { "config",       required_argument,    NULL,   'f' },
        { "log",          required_argument,    NULL,   'l' },
        { "file",	  required_argument,    NULL,   'F' },
        {0, 0, 0, 0}
    };

    static const char *short_options =
        "l:f:u:d:c:pDhC";

    int option_index = 0;

    /****************************************************************************/
    /* libpcap/PLOG (syslog sniffer) local variables                            */
    /****************************************************************************/

#ifdef HAVE_LIBPCAP
    pthread_t pcap_thread;
    pthread_attr_t thread_pcap_attr;
    pthread_attr_init(&thread_pcap_attr);
    pthread_attr_setdetachstate(&thread_pcap_attr,  PTHREAD_CREATE_DETACHED);
#endif

    /****************************************************************************/
    /* Perfmonitor local variables                                              */
    /****************************************************************************/

    pthread_t perfmonitor_thread;
    pthread_attr_t thread_perfmonitor_attr;
    pthread_attr_init(&thread_perfmonitor_attr);
    pthread_attr_setdetachstate(&thread_perfmonitor_attr,  PTHREAD_CREATE_DETACHED);

    /****************************************************************************/
    /* Various local variables						        */
    /****************************************************************************/

    /* Block all signals,  we create a signal handling thread */

    sigset_t signal_set;
    pthread_t sig_thread;
    sigfillset( &signal_set );
    pthread_sigmask( SIG_BLOCK, &signal_set, NULL );

    /* Key board handler (displays stats, etc */

    pthread_t key_thread;
    pthread_attr_t key_thread_attr;
    pthread_attr_init(&key_thread_attr);
    pthread_attr_setdetachstate(&key_thread_attr,  PTHREAD_CREATE_DETACHED);

    struct sockaddr_in sa;
    char src_dns_lookup[20];
    int  dns_flag=0;

    sbool fifoerr=0;

    char *syslog_host=NULL;
    char *syslog_facility=NULL;
    char *syslog_priority=NULL;
    char *syslog_level=NULL;
    char *syslog_tag=NULL;
    char *syslog_date=NULL;
    char *syslog_time=NULL;
    char *syslog_program=NULL;
    char *syslog_msg=NULL;

    char syslogstring[MAX_SYSLOGMSG];

    signed char c;
    char *tok;
    int rc=0;

    int i;

    time_t t;
    struct tm *run;

    sbool debugflag=0;

    /* Allocate and clear memory for global structs */

    /* Allocate memory for global struct _SaganDebug */
    debug = malloc(sizeof(_SaganDebug));
    memset(debug, 0, sizeof(_SaganDebug));

    /* Allocate memroy for global struct _SaganConfig */
    config = malloc(sizeof(_SaganConfig));
    memset(config, 0, sizeof(_SaganConfig));

    struct _SaganSigArgs *sigargs;
    sigargs = malloc(sizeof(_SaganSigArgs));
    memset(sigargs, 0, sizeof(_SaganSigArgs));

    struct _SaganDNSCache *dnscache;
    dnscache = malloc(sizeof(_SaganDNSCache));
    memset(dnscache, 0, sizeof(_SaganDNSCache));

    counters = malloc(sizeof(_SaganCounters));
    memset(counters, 0, sizeof(_SaganCounters));

    flowbit = malloc(sizeof(_Sagan_Flowbit));
    memset(flowbit, 0, sizeof(_Sagan_Flowbit));

    t = time(NULL);
    run=localtime(&t);
    strftime(config->sagan_startutime, sizeof(config->sagan_startutime), "%s",  run);

    strlcpy(config->sagan_config, CONFIG_FILE_PATH, sizeof(config->sagan_config));

    /* We set the config->sagan_log_filepath to the system default.  It'll be fopen'ed
       shortly - 06/03/2011 - Champ Clark III */

    strlcpy(config->sagan_log_filepath, SAGANLOG, sizeof(config->sagan_log_filepath));
    config->sagan_runas = RUNAS;

    /* Get command line arg's */
    while ((c = getopt_long(argc, argv, short_options, long_options, &option_index)) != -1)
        {

            switch(c)
                {

                    if (c == -1) break;

                case 'h':
                    Sagan_Usage();
                    exit(0);
                    break;

                case 'C':
                    Sagan_Credits();
                    exit(0);
                    break;

                case 'd':

                    if (Sagan_strstr(optarg, "malformed"))
                        {
                            debug->debugmalformed=1;
                            debugflag=1;
                        }

                    if (Sagan_strstr(optarg, "limits"))
                        {
                            debug->debuglimits=1;
                            debugflag=1;
                        }

                    if (Sagan_strstr(optarg, "syslog"))
                        {
                            debug->debugsyslog=1;
                            debugflag=1;
                        }

                    if (Sagan_strstr(optarg, "load"))
                        {
                            debug->debugload=1;
                            debugflag=1;
                        }

                    if (Sagan_strstr(optarg, "fwsam"))
                        {
                            debug->debugfwsam=1;
                            debugflag=1;
                        }

                    if (Sagan_strstr(optarg, "external"))
                        {
                            debug->debugexternal=1;
                            debugflag=1;
                        }

                    if (Sagan_strstr(optarg, "threads"))
                        {
                            debug->debugthreads=1;
                            debugflag=1;
                        }

                    if (Sagan_strstr(optarg, "flowbit"))
                        {
                            debug->debugflowbit=1;
                            debugflag=1;
                        }

                    if (Sagan_strstr(optarg, "engine"))
                        {
                            debug->debugengine=1;
                            debugflag=1;
                        }

                    if (Sagan_strstr(optarg, "brointel"))
                        {
                            debug->debugbrointel=1;
                            debugflag=1;
                        }

#ifdef HAVE_LIBGEOIP
                    if (Sagan_strstr(optarg, "geoip"))
                        {
                            debug->debuggeoip=1;
                            debugflag=1;
                        }
#endif

#ifdef HAVE_LIBLOGNORM
                    if (Sagan_strstr(optarg, "normalize" ))
                        {
                            debug->debugnormalize=1;
                            debugflag=1;
                        }
#endif

#ifdef HAVE_LIBESMTP
                    if (Sagan_strstr(optarg, "smtp"))
                        {
                            debug->debugesmtp=1;
                            debugflag=1;
                        }
#endif

#ifdef HAVE_LIBPCAP
                    if (Sagan_strstr(optarg, "plog"))
                        {
                            debug->debugplog=1;
                            debugflag=1;
                        }
#endif

#ifdef WITH_WEBSENSE
                    if (Sagan_strstr(optarg, "websense"))
                        {
                            debug->debugwebsense=1;
                            debugflag=1;
                        }
#endif

                    /* If option is unknown */

                    if ( debugflag == 0 )
                        {
                            fprintf(stderr, "Unknown debug option %s!\n", optarg);
                            exit(1);
                        }


                    break;

                case 'D':
                    daemonize=1;
                    break;

                case 'u':
                    config->sagan_runas=optarg;
                    break;

                case 'c':
                    Sagan_Chroot(optarg);
                    break;

                case 'F':
                    config->sagan_fifo_flag=1;
                    strlcpy(config->sagan_fifo,optarg,sizeof(config->sagan_fifo) - 1);
                    break;

                case 'f':
                    strlcpy(config->sagan_config,optarg,sizeof(config->sagan_config) - 1);
                    break;

                case 'l':
                    strlcpy(config->sagan_log_filepath,optarg,sizeof(config->sagan_log_filepath) - 1);
                    break;

                default:
                    fprintf(stderr, "Invalid argument! See below for command line switches.\n");
                    Sagan_Usage();
                    exit(0);
                    break;
                }
        }

    Sagan_Open_Log_File(OPEN, SAGAN_LOG);

    Load_Config();

    Sagan_Engine_Init();

#ifdef HAVE_LIBLOGNORM
    Sagan_Liblognorm_Load();
#endif


    /* Load/init liblognorm definitions.  I tried to move this into a subroutine,
     * but that ended up causing segfaults on ln_normalize() or causing
     * liblognorm not to function correctly (not parsing fields).  Make reloading
     * a SIGHUP a issue as well.
     * 12/17/2010 - Champ
     */

    SaganProcSyslog = malloc(config->max_processor_threads * sizeof(struct _Sagan_Proc_Syslog));
    pthread_t processor_id[config->max_processor_threads];
    pthread_attr_t thread_processor_attr;
    pthread_attr_init(&thread_processor_attr);
    pthread_attr_setdetachstate(&thread_processor_attr,  PTHREAD_CREATE_DETACHED);

    Sagan_Log(S_NORMAL, "Configuration file %s loaded and %d rules loaded.", config->sagan_config, counters->rulecount);
    Sagan_Log(S_NORMAL, "Out of %d rules, %d Flowbit(s) are in use.", counters->rulecount, counters->flowbit_total_counter);
    Sagan_Log(S_NORMAL, "Sagan version %s is firing up!", VERSION);

    /* We go ahead and assign values to SaganSigArgs (struct sig_thread_args).  This
     * struct is always used by the sig_handler thread,  and sometimes used by the
     * plog_handler (below).  So we assign values now */

    sigargs->daemonize = daemonize;

#ifdef HAVE_LIBPCAP

    /* Spawn a thread to 'sniff' syslog traffic (sagan-plog.c).  This redirects syslog
       traffic to the /dev/log socket.  This needs "root" access,  so we drop priv's
       after this thread is started */

    if ( config->plog_flag )
        {

            rc = pthread_create( &pcap_thread, NULL, (void *)plog_handler, sigargs );

            if ( rc != 0 )
                {
                    Remove_Lock_File();
                    Sagan_Log(S_ERROR, "[%s, line %d] Error creating libpcap handler thread [error: %d].", __FILE__, __LINE__, rc);
                }

            sleep(1); 	/* Sleep to avoid race between main() and plog thread
		   	plog thread needs "root" rights before sagan_droppriv().
		   	In some cases main() run sagan_droppriv() before thread
		   	can complete - Champ Clark - 07/20/2011 */

        }
#endif


    Sagan_Droppriv();              /* Become the Sagan user */
    Sagan_Log(S_NORMAL, "---------------------------------------------------------------------------");


    if ( config->perfmonitor_flag )
        {

            if (( config->perfmonitor_file_stream = fopen(config->perfmonitor_file_name, "a" )) == NULL )
                {
                    Remove_Lock_File();
                    Sagan_Log(S_ERROR, "[%s, line %d] Can't open %s - %s!", __FILE__, __LINE__, config->perfmonitor_file_name, strerror(errno));
                }


            rc = pthread_create( &perfmonitor_thread, NULL, (void *)Sagan_Perfmonitor_Handler, sigargs );

            if ( rc != 0 )
                {
                    Remove_Lock_File();
                    Sagan_Log(S_ERROR, "[%s, line %d] Error creating Perfmonitor thread [error: %d].", __FILE__, __LINE__, rc);
                }
        }


    /* Open sagan alert file */

    Sagan_Open_Log_File(OPEN, ALERT_LOG);

    /****************************************************************************
     * Display processor information as we load
     ****************************************************************************/

    /* Sagan_Track_Clients processor ********************************************/

    if ( config->sagan_track_clients_flag)
        {
            if ( config->pp_sagan_track_clients ) Sagan_Log(S_NORMAL, "Client Tracking Processor: %d minute(s)", config->pp_sagan_track_clients);
            Sagan_Track_Clients_Init();
            Sagan_Load_Tracking_Cache();
        }

    /* Sagan Blacklist IP processor *********************************************/

    if ( config->blacklist_flag)
        {
            Sagan_Blacklist_Init();
            Sagan_Blacklist_Load();
        }

    /* Sagan Websense processor ************************************************/

#ifdef WITH_WEBSENSE
    if ( config->websense_flag )
        {

            curl_global_init(CURL_GLOBAL_ALL);
            config->websense_last_time = atol(config->sagan_startutime);
            Sagan_Websense_Init();

            Sagan_Log(S_NORMAL, "");
            Sagan_Log(S_NORMAL, "Websense URL: %s", config->websense_url);
            Sagan_Log(S_NORMAL, "Websense Auth: %s", config->websense_auth);
            Sagan_Log(S_NORMAL, "Websense Device ID: %s", config->websense_device_id);
            Sagan_Log(S_NORMAL, "Websense Categories File: %s", config->websense_cat);
            Sagan_Log(S_NORMAL, "Websense Max Cache: %d", config->websense_max_cache);
            Sagan_Log(S_NORMAL, "Websense Cache Timeout: %d minutes.", config->websense_timeout  / 60);
            Sagan_Log(S_NORMAL, "Websense loaded %d categories.", counters->websense_cat_count);

        }

#endif

    /* Sagan Bro Intel processor *******************************************/

    if ( config->brointel_flag )
        {

            Sagan_Log(S_NORMAL, "");

            Sagan_BroIntel_Init();
            Sagan_BroIntel_Load_File();

            Sagan_Log(S_NORMAL, "Bro Intel::ADDR Loaded: %d", counters->brointel_addr_count);
            Sagan_Log(S_NORMAL, "Bro Intel::DOMAIN Loaded: %d", counters->brointel_domain_count);
            Sagan_Log(S_NORMAL, "Bro Intel::FILE_HASH Loaded: %d", counters->brointel_file_hash_count);
            Sagan_Log(S_NORMAL, "Bro Intel::URL Loaded: %d", counters->brointel_url_count);
            Sagan_Log(S_NORMAL, "Bro Intel::SOFTWARE Loaded: %d", counters->brointel_software_count);
            Sagan_Log(S_NORMAL, "Bro Intel::EMAIL Loaded: %d", counters->brointel_email_count);
            Sagan_Log(S_NORMAL, "Bro Intel::USER_NAME Loaded: %d", counters->brointel_user_name_count);
            Sagan_Log(S_NORMAL, "Bro Intel::FILE_NAME Loaded: %d", counters->brointel_file_name_count);
            Sagan_Log(S_NORMAL, "Bro Intel::CERT_HASH Loaded: %d", counters->brointel_cert_hash_count);
            Sagan_Log(S_NORMAL, "Bro Intel Duplicates Detected: %d", counters->brointel_dups);

        }


    /***************************************************************************
     * Output plugins
     ***************************************************************************/

#ifdef HAVE_LIBESMTP
    if ( config->sagan_esmtp_flag )
        {
            Sagan_Log(S_NORMAL, "");
            if ( config->min_email_priority ) Sagan_Log(S_NORMAL, "E-mail on priority %d or higher.", config->min_email_priority);
            Sagan_Log(S_NORMAL, "E-Mail will be sent from: %s", config->sagan_esmtp_from);
            Sagan_Log(S_NORMAL, "SMTP server is set to: %s", config->sagan_esmtp_server);
        }
#endif

#ifdef WITH_SNORTSAM

    if ( config->sagan_fwsam_flag )
        {
            Sagan_Log(S_NORMAL, "");
            Sagan_Log(S_NORMAL, "Snortsam output plug in enabled.");
        }

#endif

    if ( config->sagan_external_output_flag )
        {
            Sagan_Log(S_NORMAL, "");
            Sagan_Log(S_NORMAL, "External program to be called: %s", config->sagan_extern);
        }

    /* Unified2 ****************************************************************/

#if defined(HAVE_DNET_H) || defined(HAVE_DUMBNET_H)

    if ( config->sagan_unified2_flag )
        {
            Sagan_Log(S_NORMAL, "");
            Sagan_Log(S_NORMAL, "Unified2 file: %s", config->unified2_filepath);
            Sagan_Log(S_NORMAL, "Unified2 limit: %dM", config->unified2_limit  / 1024 / 1024 );
            Unified2InitFile();
        }

#endif

    /***************************************************************************
     * Non-Processor/Output option
     ***************************************************************************/

    /* What to "ignore" ********************************************************/

    if ( config->sagan_droplist_flag )
        {
            Load_Ignore_List();
            Sagan_Log(S_NORMAL, "");
            Sagan_Log(S_NORMAL, "Loaded %d ignore/drop list item(s).", counters->droplist_count);
        }

    /***************************************************************************
     * Continue with normal startup!
     ***************************************************************************/

    Sagan_Log(S_NORMAL, "");
    Sagan_Log(S_NORMAL, " ,-._,-. 	-*> Sagan! <*-");
    Sagan_Log(S_NORMAL, " \\/)\"(\\/	Version %s", VERSION);
    Sagan_Log(S_NORMAL, "  (_o_)	Champ Clark III & The Quadrant InfoSec Team [quadrantsec.com]");
    Sagan_Log(S_NORMAL, "  /   \\/)	Copyright (C) 2009-2015 Quadrant Information Security, et al.");
    Sagan_Log(S_NORMAL, " (|| ||) 	Using PCRE version: %s", pcre_version());
    Sagan_Log(S_NORMAL, "  oo-oo     Sagan is processing events.....");
    Sagan_Log(S_NORMAL, "");

    /* Become a daemon if requested */

    if ( daemonize )
        {
            Sagan_Log(S_NORMAL, "Becoming a daemon!");

            pid_t pid = 0;
            setsid();
            pid = fork();
            if (pid == 0) {}
            else
                {
                    exit(0);
                }
        }

    /* Create the signal handlers thread _after_ the fork() so it can properly
     * handly signals - Champ Clark III - 06/13/2011 */

    rc = pthread_create( &sig_thread, NULL, (void *)Sig_Handler, sigargs );

    if ( rc != 0  )
        {
            Remove_Lock_File();
            Sagan_Log(S_ERROR, "[%s, line %d] Error creating signal handler thread. [error: %d]", __FILE__, __LINE__, rc);
        }


    /* We don't want the key_handler() if we're in daemon mode! */

    if (!daemonize)
        {

            rc = pthread_create( &key_thread, NULL, (void *)key_handler, NULL );

            if ( rc != 0 )
                {
                    Remove_Lock_File();
                    Sagan_Log(S_ERROR, "[%s, line %d] Error creating key_handler thread. [error: %d]", __FILE__, __LINE__, rc);
                }

        }

    /* We do this after forking so init scripts can complete */

    /* Check lock file _after_ thread.  If you don't it'll retreive the wrong pid
     * and incorrectly believe there is a stale lock file if --daemon */

    checklockfile();

    Sagan_Log(S_NORMAL, "Spawning %d Processor Threads.", config->max_processor_threads);

    for (i = 0; i < config->max_processor_threads; i++)
        {

            rc = pthread_create ( &processor_id[i], &thread_processor_attr, (void *)Sagan_Processor, NULL );

            if ( rc != 0 )
                {
                    Remove_Lock_File();
                    Sagan_Log(S_ERROR, "Could not pthread_create() for I/O processors [error: %d]", rc);
                }
        }

    Sagan_Log(S_NORMAL, "");

    if ( config->sagan_fifo_flag == 0 )
        {
            Sagan_Log(S_NORMAL, "Attempting to open syslog FIFO (%s).", config->sagan_fifo);
        }
    else
        {
            Sagan_Log(S_NORMAL, "Attempting to open syslog FILE (%s).", config->sagan_fifo);
        }



    while(1)
        {

            FILE *fd;
            fd = fopen(config->sagan_fifo, "r");

            if ( config->sagan_fifo_flag == 0 )
                {
                    Sagan_Log(S_NORMAL, "Successfully opened FIFO (%s).", config->sagan_fifo);
                }
            else
                {
                    Sagan_Log(S_NORMAL, "Successfully opened FILE (%s) and processing events.....", config->sagan_fifo);
                }

            while(fd != NULL)
                {


                    while(fgets(syslogstring, sizeof(syslogstring), fd) != NULL)
                        {

                            /* If the FIFO was in a error state,  let user know the FIFO writer has resumed */

                            if ( fifoerr == 1 )
                                {
                                    Sagan_Log(S_NORMAL, "FIFO writer has restarted. Processing events.");
                                    fifoerr=0;
                                }

                            counters->sagantotal++;

                            syslog_host = strtok_r(syslogstring, "|", &tok);

                            /* If we're using DNS (and we shouldn't be!),  we start DNS checks and lookups
                             * here.  We cache both good and bad lookups to not over load our DNS server(s).
                             * The only way DNS cache can be cleared is to restart Sagan */

                            if (config->syslog_src_lookup )
                                {
                                    if ( inet_pton(AF_INET, syslog_host, &(sa.sin_addr)) == 0 )   	/* Is inbound a valid IP? */
                                        {
                                            dns_flag=0;

                                            for(i=0; i <= counters->dns_cache_count ; i++)  			/* Check cache first */
                                                {
                                                    if (!strcmp( dnscache[i].hostname, syslog_host))
                                                        {
                                                            syslog_host = dnscache[i].src_ip;
                                                            dns_flag=1;
                                                        }
                                                }

                                            /* If entry was not found in cache,  look it up */

                                            if ( dns_flag == 0 )
                                                {

                                                    /* Do a DNS lookup */
                                                    strlcpy(src_dns_lookup, DNS_Lookup(syslog_host), sizeof(src_dns_lookup));

                                                    /* Invalid lookups get the config->sagan_host value */

                                                    if (src_dns_lookup[0] == '0' )
                                                        {
                                                            strlcpy(src_dns_lookup, config->sagan_host, sizeof(src_dns_lookup));
                                                            counters->dns_miss_count++;
                                                        }


                                                    /* Add entry to DNS Cache */

                                                    dnscache = (_SaganDNSCache *) realloc(dnscache, (counters->dns_cache_count+1) * sizeof(_SaganDNSCache));
                                                    strlcpy(dnscache[counters->dns_cache_count].hostname, syslog_host, sizeof(dnscache[counters->dns_cache_count].hostname));
                                                    strlcpy(dnscache[counters->dns_cache_count].src_ip, src_dns_lookup, sizeof(dnscache[counters->dns_cache_count].src_ip));
                                                    counters->dns_cache_count++;
                                                    syslog_host = src_dns_lookup;

                                                }
                                        }

                                }
                            else
                                {

                                    /* We check to see if values from our FIFO are valid.  If we aren't doing DNS related
                                    * stuff (above),  we start basic check with the syslog_host */

                                    if (syslog_host == NULL || inet_pton(AF_INET, syslog_host, &(sa.sin_addr)) == 0  )
                                        {
                                            syslog_host = config->sagan_host;

                                            pthread_mutex_lock(&SaganMalformedCounter);
                                            counters->malformed_host++;
                                            pthread_mutex_unlock(&SaganMalformedCounter);

                                            if ( debug->debugmalformed )
                                                {
                                                    Sagan_Log(S_WARN, "Sagan received a malformed 'host' (replaced with %s)", config->sagan_host);
                                                }

                                        }
                                }

//	        if ( config->home_any == 1) {

                            /* We know check the rest of the values */

                            syslog_facility=strtok_r(NULL, "|", &tok);
                            if ( syslog_facility == NULL )
                                {
                                    syslog_facility = "SAGAN: FACILITY ERROR";

                                    pthread_mutex_lock(&SaganMalformedCounter);
                                    counters->malformed_facility++;
                                    pthread_mutex_unlock(&SaganMalformedCounter);

                                    if ( debug->debugmalformed )
                                        {
                                            Sagan_Log(S_WARN, "Sagan received a malformed 'facility'");
                                        }
                                }

                            syslog_priority=strtok_r(NULL, "|", &tok);
                            if ( syslog_priority == NULL )
                                {
                                    syslog_priority = "SAGAN: PRIORITY ERROR";

                                    pthread_mutex_lock(&SaganMalformedCounter);
                                    counters->malformed_priority++;
                                    pthread_mutex_unlock(&SaganMalformedCounter);

                                    if ( debug->debugmalformed )
                                        {
                                            Sagan_Log(S_WARN, "Sagan received a malformed 'priority'");
                                        }
                                }

                            syslog_level=strtok_r(NULL, "|", &tok);
                            if ( syslog_level == NULL )
                                {
                                    syslog_level = "SAGAN: LEVEL ERROR";

                                    pthread_mutex_lock(&SaganMalformedCounter);
                                    counters->malformed_level++;
                                    pthread_mutex_unlock(&SaganMalformedCounter);

                                    if ( debug->debugmalformed )
                                        {
                                            Sagan_Log(S_WARN, "Sagan received a malformed 'level'");
                                        }
                                }

                            syslog_tag=strtok_r(NULL, "|", &tok);
                            if ( syslog_tag == NULL )
                                {
                                    syslog_tag = "SAGAN: TAG ERROR";

                                    pthread_mutex_lock(&SaganMalformedCounter);
                                    counters->malformed_tag++;
                                    pthread_mutex_unlock(&SaganMalformedCounter);

                                    if ( debug->debugmalformed )
                                        {
                                            Sagan_Log(S_WARN, "Sagan received a malformed 'tag'");
                                        }
                                }

                            syslog_date=strtok_r(NULL, "|", &tok);
                            if ( syslog_date == NULL )
                                {
                                    syslog_date = "SAGAN: DATE ERROR";

                                    pthread_mutex_lock(&SaganMalformedCounter);
                                    counters->malformed_date++;
                                    pthread_mutex_unlock(&SaganMalformedCounter);

                                    if ( debug->debugmalformed )
                                        {
                                            Sagan_Log(S_WARN, "Sagan received a malformed 'date'");
                                        }
                                }

                            syslog_time=strtok_r(NULL, "|", &tok);
                            if ( syslog_time == NULL )
                                {
                                    syslog_time = "SAGAN: TIME ERROR";

                                    pthread_mutex_lock(&SaganMalformedCounter);
                                    counters->malformed_time++;
                                    pthread_mutex_unlock(&SaganMalformedCounter);

                                    if ( debug->debugmalformed )
                                        {
                                            Sagan_Log(S_WARN, "Sagan received a malformed 'time'");
                                        }
                                }


                            syslog_program=strtok_r(NULL, "|", &tok);
                            if ( syslog_program == NULL )
                                {
                                    syslog_program = "SAGAN: PROGRAM ERROR";

                                    pthread_mutex_lock(&SaganMalformedCounter);
                                    counters->malformed_program++;
                                    pthread_mutex_unlock(&SaganMalformedCounter);

                                    if ( debug->debugmalformed )
                                        {
                                            Sagan_Log(S_WARN, "Sagan received a malformed 'program'");
                                        }
                                }

                            syslog_msg=strtok_r(NULL, "", &tok);		/* In case the message has | in it,  we delimit on "" */
                            if ( syslog_msg == NULL )
                                {
                                    syslog_msg = "SAGAN: MESSAGE ERROR";

                                    pthread_mutex_lock(&SaganMalformedCounter);
                                    counters->malformed_message++;
                                    pthread_mutex_unlock(&SaganMalformedCounter);

                                    if ( debug->debugmalformed )
                                        {
                                            Sagan_Log(S_WARN, "Sagan received a malformed 'message' [Syslog Host: %s]", syslog_host);
                                        }

                                    /* If the message is lost,  all is lost.  Typically,  you don't lose part of the message,
                                     * it's more likely to lose all  - Champ Clark III 11/17/2011 */

                                    counters->sagan_log_drop++;

                                }


                            /* Strip any \n or \r from the syslog_msg */

                            if ( strcspn ( syslog_msg, "\n" ) < strlen(syslog_msg) )
                                syslog_msg[strcspn ( syslog_msg, "\n" )] = '\0';

                            if ( proc_msgslot < config->max_processor_threads )
                                {

                                    pthread_mutex_lock(&SaganProcWorkMutex);

                                    strlcpy(SaganProcSyslog[proc_msgslot].syslog_host, syslog_host, sizeof(SaganProcSyslog[proc_msgslot].syslog_host));
                                    strlcpy(SaganProcSyslog[proc_msgslot].syslog_facility, syslog_facility, sizeof(SaganProcSyslog[proc_msgslot].syslog_facility));
                                    strlcpy(SaganProcSyslog[proc_msgslot].syslog_priority, syslog_priority, sizeof(SaganProcSyslog[proc_msgslot].syslog_priority));
                                    strlcpy(SaganProcSyslog[proc_msgslot].syslog_level, syslog_level, sizeof(SaganProcSyslog[proc_msgslot].syslog_level));
                                    strlcpy(SaganProcSyslog[proc_msgslot].syslog_tag, syslog_tag, sizeof(SaganProcSyslog[proc_msgslot].syslog_tag));
                                    strlcpy(SaganProcSyslog[proc_msgslot].syslog_date, syslog_date, sizeof(SaganProcSyslog[proc_msgslot].syslog_date));
                                    strlcpy(SaganProcSyslog[proc_msgslot].syslog_time, syslog_time, sizeof(SaganProcSyslog[proc_msgslot].syslog_time));
                                    strlcpy(SaganProcSyslog[proc_msgslot].syslog_program, syslog_program, sizeof(SaganProcSyslog[proc_msgslot].syslog_program));
                                    strlcpy(SaganProcSyslog[proc_msgslot].syslog_message, syslog_msg, sizeof(SaganProcSyslog[proc_msgslot].syslog_message));

                                    proc_msgslot++;

                                    pthread_cond_signal(&SaganProcDoWork);
                                    pthread_mutex_unlock(&SaganProcWorkMutex);
                                }
                            else
                                {
                                    counters->worker_thread_exhaustion++;
                                    counters->sagan_log_drop++;
                                }

                            if (debug->debugthreads) Sagan_Log(S_DEBUG, "Current \"proc_msgslot\": %d", proc_msgslot);

                            if (debug->debugsyslog)
                                {

                                    Sagan_Log(S_DEBUG, "[%s, line %d] **[RAW Syslog]*********************************", __FILE__, __LINE__);
                                    Sagan_Log(S_DEBUG, "[%s, line %d] Host: %s | Program: %s | Facility: %s | Priority: %s | Level: %s | Tag: %s", __FILE__, __LINE__, syslog_host, syslog_program, syslog_facility, syslog_priority, syslog_level, syslog_tag);
                                    Sagan_Log(S_DEBUG, "[%s, line %d] Raw message: %s", __FILE__, __LINE__, syslog_msg);

                                }


                        } /* while(fgets) */

                    /* fgets() has returned a error,  likely due to the FIFO writer leaving */

                    /* DEBUG : set a kill flag and join */
                    /* RMEOVE LOCK */

                    if ( fifoerr == 0 )
                        {
                            if ( config->sagan_fifo_flag != 0 )
                                {
                                    Sagan_Log(S_NORMAL, "EOF reached. Waiting for threads to catch up");
                                    sleep(5);
                                    fclose(fd);
                                    Sagan_Log(S_NORMAL, "Exiting.");		/* DEBUG: Rejoin threads */
                                    exit(0);
                                }
                            else
                                {
                                    Sagan_Log(S_WARN, "FIFO writer closed.  Waiting for FIFO writer to restart....");
                                    fifoerr=1; 			/* Set flag so our wile(fgets) knows */
                                }
                        }
                    sleep(1);		/* So we don't eat 100% CPU */

                } /* while(fd != NULL)  */

            fclose(fd); 			/* ???? */

        } /* End of while(1) */

} /* End of main */
Example #2
0
void Sig_Handler( _SaganSigArgs *args )
{

    sigset_t signal_set;
    int sig;
    sbool orig_perfmon_value = 0;

#ifdef HAVE_LIBPCAP
    sbool orig_plog_value = 0;
#endif

    for(;;)
        {
            /* wait for any and all signals */
            sigfillset( &signal_set );
            sigwait( &signal_set, &sig );


            switch( sig )
                {
                    /* exit */
                case SIGQUIT:
                case SIGINT:
                case SIGTERM:
                case SIGSEGV:
                case SIGABRT:

                    Sagan_Log(S_NORMAL, "\n\n[Received signal %d. Sagan version %s shutting down]-------\n", sig, VERSION);
                    Sagan_Statistics();

#if defined(HAVE_DNET_H) || defined(HAVE_DUMBNET_H)
                    if ( sagan_unified2_flag )
                        {
                            Unified2CleanExit();
                        }
#endif

#ifdef HAVE_LIBMAXMINDDB

                    MMDB_close(&config->geoip2);

#endif

                    fflush(config->sagan_alert_stream);
                    fclose(config->sagan_alert_stream);             /* Close Sagan alert file */

                    fflush(config->sagan_log_stream);               /* Close the sagan.log */
                    fclose(config->sagan_log_stream);

                    if ( config->perfmonitor_flag )
                        {
                            Sagan_Perfmonitor_Close();
                        }

                    Remove_Lock_File();
                    exit(0);
                    break;

                case SIGHUP:

                    config->sagan_reload = 1;				/* Only this thread can alter this */

                    pthread_mutex_lock(&SaganReloadMutex);

                    Sagan_Log(S_NORMAL, "[Reloading Sagan version %s.]-------", VERSION);

                    /*
                    * Close and re-open log files.  This is for logrotate and such
                    * 04/14/2015 - Champ Clark III ([email protected])
                    */

                    Sagan_Open_Log_File(REOPEN, ALL_LOGS);

                    /******************/
                    /* Reset counters */
                    /******************/

                    counters->refcount=0;
                    counters->classcount=0;
                    counters->rulecount=0;
                    counters->ruletotal=0;
                    counters->genmapcount=0;
                    counters->flowbit_track_count=0;

                    memset(rulestruct, 0, sizeof(_Rule_Struct));
                    memset(classstruct, 0, sizeof(_Class_Struct));
                    memset(generator, 0, sizeof(_Sagan_Processor_Generator));
                    memset(flowbit, 0, sizeof(_Sagan_Flowbit));


                    /**********************************/
                    /* Disabled and reset processors. */
                    /**********************************/

                    /* Note: Processors that run as there own thread (perfmon, plog) cannot be
                     * loaded via SIGHUP.  They must be loaded at run time.  Once they are loaded,
                     * they can be disabled/re-enabled. */

                    /* Single Threaded processors */

                    if ( config->perfmonitor_flag == 1 && orig_perfmon_value == 0 )
                        {
                            Sagan_Perfmonitor_Close();
                            orig_perfmon_value = 1;
                        }

                    config->perfmonitor_flag = 0;

#ifdef HAVE_LIBPCAP

                    if ( config->plog_flag )
                        {
                            orig_plog_value = 1;
                        }

                    config->plog_flag = 0;
#endif

                    /* Multi Threaded processors */

                    config->blacklist_flag = 0;

                    if ( config->blacklist_flag )
                        {
                            free(SaganBlacklist);
                        }

                    config->blacklist_flag = 0;

                    if ( config->brointel_flag )
                        {
                            free(Sagan_BroIntel_Intel_Addr);
                            free(Sagan_BroIntel_Intel_Domain);
                            free(Sagan_BroIntel_Intel_File_Hash);
                            free(Sagan_BroIntel_Intel_URL);
                            free(Sagan_BroIntel_Intel_Software);
                            free(Sagan_BroIntel_Intel_Email);
                            free(Sagan_BroIntel_Intel_User_Name);
                            free(Sagan_BroIntel_Intel_File_Name);
                            free(Sagan_BroIntel_Intel_Cert_Hash);

                            counters->brointel_addr_count = 0;
                            counters->brointel_domain_count = 0;
                            counters->brointel_file_hash_count = 0;
                            counters->brointel_url_count = 0;
                            counters->brointel_software_count = 0;
                            counters->brointel_email_count = 0;
                            counters->brointel_user_name_count = 0;
                            counters->brointel_file_name_count = 0;
                            counters->brointel_cert_hash_count = 0;
                            counters->brointel_dups = 0;
                        }

                    config->brointel_flag = 0;

                    if ( config->sagan_track_clients_flag )
                        {
                            free(SaganTrackClients);
                            fclose(config->sagan_track_client_file);
                        }

                    config->sagan_track_clients_flag = 0;
                    counters->track_clients_client_count = 0;
                    counters->track_clients_down = 0;

                    /* Output formats */

                    config->sagan_ext_flag = 0;

#ifdef WITH_SYSLOG
                    config->sagan_syslog_flag = 0;
#endif


#ifdef HAVE_LIBESMTP
                    config->sagan_esmtp_flag = 0;
#endif

#ifdef WITH_SNORTSAM
                    config->sagan_fwsam_flag = 0;
#endif

                    /* Non-output / Processors */

                    if ( config->sagan_droplist_flag )
                        {
                            config->sagan_droplist_flag = 0;
                            free(SaganIgnorelist);
                        }

                    /************************************************************/
                    /* Re-load primary configuration (rules/classifictions/etc) */
                    /************************************************************/

                    Load_Config();	/* <- RELOAD */

                    /************************************************************/
                    /* Re-load primary configuration (rules/classifictions/etc) */
                    /************************************************************/

                    if ( config->perfmonitor_flag == 1 )
                        {
                            if ( orig_perfmon_value == 1 )
                                {
                                    Sagan_Perfmonitor_Open();
                                }
                            else
                                {
                                    Sagan_Log(S_WARN, "** 'perfmonitor' must be loaded at runtime! NOT loading 'perfmonitor'!");
                                    config->perfmonitor_flag = 0;
                                }
                        }


#ifdef HAVE_LIBPCAP

                    if ( config->plog_flag == 1 )
                        {
                            if ( orig_plog_value == 1 )
                                {
                                    config->plog_flag = 1;
                                }
                            else
                                {
                                    Sagan_Log(S_WARN, "** 'plog' must be loaded at runtime! NOT loading 'plog'!");
                                    config->plog_flag = 0;
                                }
                        }
#endif

                    /* Load Blacklist data */

                    if ( config->blacklist_flag )
                        {
                            counters->blacklist_count=0;
                            Sagan_Blacklist_Init();
                            Sagan_Blacklist_Load();
                        }

                    if ( config->brointel_flag )
                        {
                            Sagan_BroIntel_Init();
                            Sagan_BroIntel_Load_File();
                        }

                    if ( config->sagan_track_clients_flag )
                        {
                            Sagan_Load_Tracking_Cache();
                            Sagan_Log(S_NORMAL, "Reset Sagan Track Client.");
                        }


                    /* Non output / processors */

                    if ( config->sagan_droplist_flag )
                        {
                            Load_Ignore_List();
                            Sagan_Log(S_NORMAL, "Loaded %d ignore/drop list item(s).", counters->droplist_count);
                        }

#ifdef HAVE_LIBMAXMINDDB
                    Sagan_Log(S_NORMAL, "Reloading GeoIP2 data.");
                    Sagan_Open_GeoIP2_Database();
#endif

#ifdef HAVE_LIBLOGNORM
                    Sagan_Liblognorm_Load();
#endif


                    pthread_cond_signal(&SaganReloadCond);
                    pthread_mutex_unlock(&SaganReloadMutex);

                    config->sagan_reload = 0;

                    Sagan_Log(S_NORMAL, "Configuration reloaded.");
                    break;

                    /* Signals to ignore */
                case 17:		/* Child process has exited. */
                case 28:		/* Terminal 'resize'/alarm. */
                    break;

                case SIGUSR1:
                    Sagan_Statistics();
                    break;

                default:
                    Sagan_Log(S_NORMAL, "[Received signal %d. Sagan doesn't know how to deal with]", sig);
                }
        }
}