Пример #1
0
int parse_proto_program( char *program )
{

    int i;

    for (i = 0; i < counters->mapcount_program; i++)
        {

            if ( map_program[i].nocase == 1 )
                {
                    if (Sagan_stristr(program, map_program[i].program, TRUE)) return(map_program[i].proto);
                }
            else
                {
                    if (Sagan_strstr(program, map_program[i].program)) return(map_program[i].proto);
                }
        }
    return(0);
}
Пример #2
0
int parse_proto( char *msg )
{

    int i;

    for (i = 0; i < counters->mapcount_message; i++)
        {

            if ( map_message[i].nocase == 1 )
                {
                    if (Sagan_stristr(msg, map_message[i].search, TRUE)) return(map_message[i].proto);
                }
            else
                {
                    if (Sagan_strstr(msg, map_message[i].search)) return(map_message[i].proto);
                }
        }
    return(0);
}
Пример #3
0
char *Sagan_Parse_IP( char *syslogmessage, int pos )
{

    int result_space, result_nonspace, i, b;

    int flag=0;
    int current_pos=0;
    int notfound=0;

    char ctmp[2] = { 0 };
    char lastgood[16] = { 0 };
    char msg[MAX_SYSLOGMSG] = { 0 };
    char tmpmsg[MAX_SYSLOGMSG] = { 0 };

    char *retbuf = NULL;
    char *tok=NULL;
    char *ptmp=NULL;

    struct sockaddr_in sa;

    snprintf(tmpmsg, sizeof(tmpmsg), "%s", syslogmessage);

    ptmp = strtok_r(tmpmsg, " ", &tok);

    while (ptmp != NULL )
        {

            if (Sagan_strstr(ptmp, "."))
                {

                    result_space = inet_pton(AF_INET, ptmp,  &(sa.sin_addr));

                    /* If we already have a good IP,  return it.  We can sometimes skips
                     * the next steps */

                    if ( result_space != 0 && strcmp(ptmp, "127.0.0.1"))
                        {

                            current_pos++;

                            if ( current_pos == pos )
                                {
                                    return(ptmp);
                                }
                        }
                    else
                        {
                            notfound = 1;
                        }

                    /* Start tearing apart the substring */

                    if ( notfound == 1 )
                        {

                            for (b=0; b < strlen(ptmp); b++)
                                {
                                    for (i = b; i < strlen(ptmp); i++)
                                        {

                                            snprintf(ctmp, sizeof(ctmp), "%c", ptmp[i]);
                                            strlcat(msg, ctmp, sizeof(msg));

                                            result_nonspace = inet_pton(AF_INET, msg,  &(sa.sin_addr));

                                            if ( result_nonspace != 0 )
                                                {
                                                    strlcpy(lastgood, msg, sizeof(lastgood));
                                                    flag=1;
                                                }

                                            if ( flag == 1 && result_nonspace == 0 )
                                                {

                                                    current_pos++;

                                                    if ( current_pos == pos )
                                                        {
                                                            if (!strcmp(lastgood, "127.0.0.1")) return(config->sagan_host);
                                                            retbuf=lastgood;
                                                            return(retbuf);
                                                        }

                                                    flag = 0;
                                                    i=i+strlen(lastgood);
                                                    b=b+strlen(lastgood);
                                                    break;
                                                }
                                        }
                                    strlcpy(msg, "", sizeof(msg));
                                }
                        }
                    notfound = 0;
                }
            ptmp = strtok_r(NULL, " ", &tok);
        }

    return("0");
}
int Sagan_Flowbit_Condition(int rule_position, char *ip_src_char, char *ip_dst_char )
{

    time_t t;
    struct tm *now;
    char  timet[20];
    char  tmp[128] = { 0 };
    char *tmp_flowbit_name = NULL;
    char *tok = NULL;

    int i;
    int a;

    uint32_t ip_src;
    uint32_t ip_dst;

    sbool flowbit_match = 0;
    int flowbit_total_match = 0;

    t = time(NULL);
    now=localtime(&t);
    strftime(timet, sizeof(timet), "%s",  now);

    ip_src = IP2Bit(ip_src_char);
    ip_dst = IP2Bit(ip_dst_char);

    int and_or = 0;

    Sagan_Flowbit_Cleanup();

    for (i = 0; i < rulestruct[rule_position].flowbit_count; i++)
        {

            /*******************
             *      ISSET      *
             *******************/

            if ( rulestruct[rule_position].flowbit_type[i] == 3 )
                {

                    for (a = 0; a < counters_ipc->flowbit_count; a++)
                        {

                            strlcpy(tmp, rulestruct[rule_position].flowbit_name[i], sizeof(tmp));

                            if (Sagan_strstr(rulestruct[rule_position].flowbit_name[i], "|"))
                                {
                                    tmp_flowbit_name = strtok_r(tmp, "|", &tok);
                                    and_or = 1;
                                }
                            else
                                {
                                    tmp_flowbit_name = strtok_r(tmp, "&", &tok);
                                    and_or = 0; 					/* Need this? */
                                }

                            while (tmp_flowbit_name != NULL )
                                {

                                    if (!strcmp(tmp_flowbit_name, flowbit_ipc[a].flowbit_name) &&
                                            flowbit_ipc[a].flowbit_state == 1 )
                                        {

                                            /* direction: none */

                                            if ( rulestruct[rule_position].flowbit_direction[i] == 0 )

                                                {

                                                    if ( debug->debugflowbit)
                                                        {
                                                            Sagan_Log(S_DEBUG, "[%s, line %d] \"isset\" flowbit \"%s\" (direction: \"none\"). (any -> any)", __FILE__, __LINE__, flowbit_ipc[a].flowbit_name);
                                                        }

                                                    flowbit_total_match++;
                                                }

                                            /* direction: both */

                                            if ( rulestruct[rule_position].flowbit_direction[i] == 1 &&
                                                    flowbit_ipc[a].ip_src == ip_src &&
                                                    flowbit_ipc[a].ip_dst == ip_dst )

                                                {

                                                    if ( debug->debugflowbit)
                                                        {
                                                            Sagan_Log(S_DEBUG, "[%s, line %d] \"isset\" flowbit \"%s\" (direction: \"both\"). (%s -> %s)", __FILE__, __LINE__, flowbit_ipc[a].flowbit_name, ip_src_char, ip_dst_char);
                                                        }

                                                    flowbit_total_match++;
                                                }

                                            /* direction: by_src */

                                            if ( rulestruct[rule_position].flowbit_direction[i] == 2 &&
                                                    flowbit_ipc[a].ip_src == ip_src )

                                                {

                                                    if ( debug->debugflowbit)
                                                        {
                                                            Sagan_Log(S_DEBUG, "[%s, line %d] \"isset\" flowbit \"%s\" (direction: \"by_src\"). (%s -> any)", __FILE__, __LINE__, flowbit_ipc[a].flowbit_name, ip_src_char);
                                                        }

                                                    flowbit_total_match++;
                                                }

                                            /* direction: by_dst */

                                            if ( rulestruct[rule_position].flowbit_direction[i] == 3 &&
                                                    flowbit_ipc[a].ip_dst == ip_dst )

                                                {

                                                    if ( debug->debugflowbit)
                                                        {
                                                            Sagan_Log(S_DEBUG, "[%s, line %d] \"isset\" flowbit \"%s\" (direction: \"by_dst\"). (any -> %s)", __FILE__, __LINE__, flowbit_ipc[a].flowbit_name, ip_dst_char);
                                                        }

                                                    flowbit_total_match++;
                                                }

                                            /* direction: reverse */

                                            if ( rulestruct[rule_position].flowbit_direction[i] == 4 &&
                                                    flowbit_ipc[a].ip_src == ip_dst &&
                                                    flowbit_ipc[a].ip_dst == ip_src )

                                                {
                                                    if ( debug->debugflowbit)
                                                        {
                                                            Sagan_Log(S_DEBUG, "[%s, line %d] \"isset\" flowbit \"%s\" (direction: \"reverse\"). (%s -> %s)", __FILE__, __LINE__, flowbit_ipc[a].flowbit_name, ip_dst_char, ip_src_char);
                                                        }

                                                    flowbit_total_match++;
                                                }

                                        } /* End of strcmp flowbit_name & flowbit_state = 1 */


                                    if ( and_or == 1)
                                        {
                                            tmp_flowbit_name = strtok_r(NULL, "|", &tok);
                                        }
                                    else
                                        {
                                            tmp_flowbit_name = strtok_r(NULL, "&", &tok);
                                        }

                                } /* End of "while tmp_flowbit_name" */

                        } /* End of "for a" */

                } /* End "if" flowbit_type == 3 (ISSET) */

            /*******************
            *    ISNOTSET     *
            *******************/

            if ( rulestruct[rule_position].flowbit_type[i] == 4 )
                {

                    flowbit_match = 0;

                    for (a = 0; a < counters_ipc->flowbit_count; a++)
                        {

                            strlcpy(tmp, rulestruct[rule_position].flowbit_name[i], sizeof(tmp));

                            if (Sagan_strstr(rulestruct[rule_position].flowbit_name[i], "|"))
                                {
                                    tmp_flowbit_name = strtok_r(tmp, "|", &tok);
                                    and_or = 1;
                                }
                            else
                                {
                                    tmp_flowbit_name = strtok_r(tmp, "&", &tok);
                                    and_or = 0;                                  /* Need this? */
                                }

                            while (tmp_flowbit_name != NULL )
                                {

                                    if (!strcmp(tmp_flowbit_name, flowbit_ipc[a].flowbit_name))
                                        {


                                            flowbit_match=1;


                                            if ( flowbit_ipc[a].flowbit_state == 0 )
                                                {

                                                    /* direction: none */

                                                    if ( rulestruct[rule_position].flowbit_direction[i] == 0 )
                                                        {

                                                            if ( debug->debugflowbit)
                                                                {
                                                                    Sagan_Log(S_DEBUG, "[%s, line %d] \"isnotset\" flowbit \"%s\" (direction: \"none\"). (any -> any)", __FILE__, __LINE__, flowbit_ipc[a].flowbit_name);
                                                                }

                                                            flowbit_total_match++;
                                                        }

                                                    /* direction: both */

                                                    if ( rulestruct[rule_position].flowbit_direction[i] == 1 )
                                                        {


                                                            if ( flowbit_ipc[a].ip_src == ip_src &&
                                                                    flowbit_ipc[a].ip_dst == ip_dst )
                                                                {

                                                                    if ( debug->debugflowbit)
                                                                        {
                                                                            Sagan_Log(S_DEBUG, "[%s, line %d] \"isnotset\" flowbit \"%s\" (direction: \"both\"). (%s -> %s)", __FILE__, __LINE__, flowbit_ipc[a].flowbit_name, ip_src_char, ip_dst_char);
                                                                        }

                                                                    flowbit_total_match++;
                                                                }
                                                        }

                                                    /* direction: by_src */

                                                    if ( rulestruct[rule_position].flowbit_direction[i] == 2 )
                                                        {

                                                            if ( flowbit_ipc[a].ip_src == ip_src )
                                                                {

                                                                    if ( debug->debugflowbit)
                                                                        {
                                                                            Sagan_Log(S_DEBUG, "[%s, line %d] \"isnotset\" flowbit \"%s\" (direction: \"by_src\"). (%s -> any)", __FILE__, __LINE__, flowbit_ipc[a].flowbit_name, ip_src_char);
                                                                        }

                                                                    flowbit_total_match++;
                                                                }
                                                        }

                                                    /* direction: by_dst */

                                                    if ( rulestruct[rule_position].flowbit_direction[i] == 3 )
                                                        {

                                                            if ( flowbit_ipc[a].ip_dst == ip_dst )
                                                                {

                                                                    if ( debug->debugflowbit)
                                                                        {
                                                                            Sagan_Log(S_DEBUG, "[%s, line %d] \"isnotset\" flowbit \"%s\" (direction: \"by_dst\"). (any -> %s)", __FILE__, __LINE__, flowbit_ipc[a].flowbit_name, ip_dst_char);
                                                                        }

                                                                    flowbit_total_match++;
                                                                }
                                                        }

                                                    /* direction: reverse */

                                                    if ( rulestruct[rule_position].flowbit_direction[i] == 4 )
                                                        {

                                                            if ( flowbit_ipc[a].ip_src == ip_dst &&
                                                                    flowbit_ipc[a].ip_dst == ip_src )
                                                                {

                                                                    if ( debug->debugflowbit)
                                                                        {
                                                                            Sagan_Log(S_DEBUG, "[%s, line %d] \"isnotset\" flowbit \"%s\" (direction: \"reverse\"). (%s -> %s)", __FILE__, __LINE__, flowbit_ipc[a].flowbit_name, ip_dst_char, ip_src_char);
                                                                        }

                                                                    flowbit_total_match++;
                                                                }
                                                        }

                                                } /* End flowbit_state == 0 */

                                        } /* End of strcmp flowbit_name */

                                    if ( and_or == 1)
                                        {
                                            tmp_flowbit_name = strtok_r(NULL, "|", &tok);
                                        }
                                    else
                                        {
                                            tmp_flowbit_name = strtok_r(NULL, "&", &tok);
                                        }

                                } /* End of "while tmp_flowbit_name" */
                        } /* End of "for a" */

                    if ( and_or == 1 && flowbit_match == 1 )
                        {
                            flowbit_total_match = rulestruct[rule_position].flowbit_condition_count;	/* Do we even need this for OR? */
                        }

                    if ( and_or == 0 && flowbit_match == 0 )
                        {
                            flowbit_total_match = rulestruct[rule_position].flowbit_condition_count;
                        }

                } /* End of "flowbit_type[i] == 4" */

        } /* End of "for i" */

    /* IF we match all criteria for isset/isnotset
     *
     * If we match the flowbit_conditon_count (number of concurrent flowbits)
     * we trigger.  It it's an "or" statement,  we trigger if any of the
     * flowbits are set.
     *
     */

    if ( ( rulestruct[rule_position].flowbit_condition_count == flowbit_total_match ) || ( and_or == 1 && flowbit_total_match != 0 ) )
        {

            if ( debug->debugflowbit)
                {
                    Sagan_Log(S_DEBUG, "[%s, line %d] Condition of flowbit returning TRUE. %d %d", __FILE__, __LINE__, rulestruct[rule_position].flowbit_condition_count, flowbit_total_match);
                }

            return(true);
        }

    /* isset/isnotset failed. */

    if ( debug->debugflowbit)
        {
            Sagan_Log(S_DEBUG, "[%s, line %d] Condition of flowbit returning FALSE. %d %d", __FILE__, __LINE__, rulestruct[rule_position].flowbit_condition_count, flowbit_total_match);
        }

    return(false);

}  /* End of Sagan_Flowbit_Condition(); */
void Sagan_Processor ( void )
{

    struct _Sagan_Proc_Syslog *SaganProcSyslog_LOCAL = NULL;
    SaganProcSyslog_LOCAL = malloc(sizeof(struct _Sagan_Proc_Syslog));

    if ( SaganProcSyslog_LOCAL == NULL )
        {
            Sagan_Log(S_ERROR, "[%s, line %d] Failed to allocate memory for SaganProcSyslog_LOCAL. Abort!", __FILE__, __LINE__);
        }

    memset(SaganProcSyslog_LOCAL, 0, sizeof(struct _Sagan_Proc_Syslog));

    sbool ignore_flag=0;

    int i;

    for (;;)
        {

            pthread_mutex_lock(&SaganProcWorkMutex);

            while ( proc_msgslot == 0 ) pthread_cond_wait(&SaganProcDoWork, &SaganProcWorkMutex);

            if ( config->sagan_reload == 1 )
                {
                    pthread_cond_wait(&SaganReloadCond, &SaganReloadMutex);
                }

            proc_msgslot--;	/* This was ++ before coming over, so we now -- it to get to
					 * original value */

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

            pthread_mutex_unlock(&SaganProcWorkMutex);

            /* Check for general "drop" items.  We do this first so we can save CPU later */

            if ( config->sagan_droplist_flag )
                {

                    ignore_flag=0;

                    for (i = 0; i < counters->droplist_count; i++)
                        {

                            if (Sagan_strstr(SaganProcSyslog_LOCAL->syslog_message, SaganIgnorelist[i].ignore_string))
                                {

                                    pthread_mutex_lock(&SaganIgnoreCounter);
                                    counters->ignore_count++;
                                    pthread_mutex_unlock(&SaganIgnoreCounter);

                                    ignore_flag=1;
                                    goto outside_loop;	/* Stop processing from ignore list */
                                }
                        }
                }

outside_loop:

            /* If we're in a ignore state,  then we can bypass the processors */

            if ( ignore_flag == 0 )
                {

                    Sagan_Engine(SaganProcSyslog_LOCAL);

                    if ( config->sagan_track_clients_flag )
                        {

                            Sagan_Track_Clients( IP2Bit(SaganProcSyslog_LOCAL->syslog_host) );

                        }


                } // End if if (ignore_Flag)


        } //  for (;;)

    Sagan_Log(S_WARN, "[%s, line %d] Holy cow! You should never see this message!", __FILE__, __LINE__);
    free(SaganProcSyslog_LOCAL);		/* Should never make it here */
}
Пример #6
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 */