"Fossies" - the Fresh Open Source Software Archive

Member "snort-2.9.17/src/util.c" (16 Oct 2020, 69857 Bytes) of package /linux/misc/snort-2.9.17.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "util.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.9.16.1_vs_2.9.17.

    1 /* $Id$ */
    2 /*
    3 ** Copyright (C) 2014-2020 Cisco and/or its affiliates. All rights reserved.
    4 ** Copyright (C) 2002-2013 Sourcefire, Inc.
    5 ** Copyright (C) 2002 Martin Roesch <roesch@sourcefire.com>
    6 **
    7 ** This program is free software; you can redistribute it and/or modify
    8 ** it under the terms of the GNU General Public License Version 2 as
    9 ** published by the Free Software Foundation.  You may not use, modify or
   10 ** distribute this program under any other version of the GNU General
   11 ** Public License.
   12 **
   13 ** This program is distributed in the hope that it will be useful,
   14 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
   15 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16 ** GNU General Public License for more details.
   17 **
   18 ** You should have received a copy of the GNU General Public License
   19 ** along with this program; if not, write to the Free Software
   20 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
   21 */
   22 
   23 
   24 #ifdef HAVE_CONFIG_H
   25 #include "config.h"
   26 #endif
   27 
   28 #include <sys/types.h>
   29 
   30 #ifndef WIN32
   31 #include <sys/socket.h>
   32 #include <netinet/in.h>
   33 #include <arpa/inet.h>
   34 #include <sys/wait.h>
   35 #include <dirent.h>
   36 #include <fnmatch.h>
   37 #endif /* !WIN32 */
   38 
   39 #include <stdarg.h>
   40 #include <syslog.h>
   41 #include <errno.h>
   42 #include <sys/stat.h>
   43 #include <time.h>
   44 #include <signal.h>
   45 #include <unistd.h>
   46 #include <pcap.h>
   47 #include <timersub.h>
   48 #include <pthread.h>
   49 #include <string.h>
   50 
   51 #ifdef HAVE_MALLINFO
   52 #include <malloc.h>
   53 static struct mallinfo mi;
   54 #endif
   55 
   56 #ifndef WIN32
   57 #include <grp.h>
   58 #include <pwd.h>
   59 #include <netdb.h>
   60 #include <limits.h>
   61 #endif /* !WIN32 */
   62 
   63 #include <fcntl.h>
   64 
   65 #ifdef HAVE_STRINGS_H
   66 #include <strings.h>
   67 #endif
   68 
   69 #include <zlib.h>
   70 
   71 #include "snort.h"
   72 #include "mstring.h"
   73 #include "snort_debug.h"
   74 #include "util.h"
   75 #include "parser.h"
   76 #include "sfdaq.h"
   77 #include "build.h"
   78 #include "plugbase.h"
   79 #include "sf_types.h"
   80 #include "sflsq.h"
   81 #include "pcre.h"
   82 #include "mpse.h"
   83 #include "ppm.h"
   84 #include "active.h"
   85 #include "packet_time.h"
   86 #include "control/sfcontrol.h"
   87 
   88 #ifdef TARGET_BASED
   89 #include "sftarget_reader.h"
   90 #endif
   91 
   92 #ifdef SIDE_CHANNEL
   93 #include "sidechannel.h"
   94 #endif
   95 
   96 #ifdef WIN32
   97 #include "win32/WIN32-Code/name.h"
   98 #endif
   99 
  100 #include "stream_common.h"
  101 
  102 #ifdef PATH_MAX
  103 #define PATH_MAX_UTIL PATH_MAX
  104 #else
  105 #define PATH_MAX_UTIL 1024
  106 #endif /* PATH_MAX */
  107 
  108 extern PreprocStatsFuncNode *preproc_stats_funcs;
  109 
  110 // You may need to adjust this on the systems which don't have standard paths
  111 // defined.
  112 #ifndef _PATH_VARRUN
  113 static char _PATH_VARRUN[STD_BUF];
  114 #endif
  115 
  116 /****************************************************************************
  117  * Store interesting data in memory that would not otherwise be visible
  118  * in a CORE(5) file
  119  ***************************************************************************/
  120 #define SNORT_VERSION_STRING ("### Snort Version "VERSION" Build "BUILD"\n")
  121 #define SNORT_VERSION_STRLEN sizeof(SNORT_VERSION_STRING)
  122 char __snort_version_string[SNORT_VERSION_STRLEN];
  123 
  124 void StoreSnortInfoStrings( void )
  125 {
  126     strncpy(__snort_version_string, SNORT_VERSION_STRING,
  127             sizeof(__snort_version_string));
  128 }
  129 #undef SNORT_VERSION_STRING
  130 #undef SNORT_VERSION_STRLEN
  131 
  132 /****************************************************************************
  133  *
  134  * Function: CalcPct(uint64_t, uint64_t)
  135  *
  136  * Purpose:  Calculate the percentage of a value compared to a total
  137  *
  138  * Arguments: cnt => the numerator in the equation
  139  *            total => the denominator in the calculation
  140  *
  141  * Returns: pct -> the percentage of cnt to value
  142  *
  143  ****************************************************************************/
  144 double CalcPct(uint64_t cnt, uint64_t total)
  145 {
  146     double pct = 0.0;
  147 
  148     if (total == 0.0)
  149     {
  150         pct = (double)cnt;
  151     }
  152     else
  153     {
  154         pct = (double)cnt / (double)total;
  155     }
  156 
  157     pct *= 100.0;
  158 
  159     return pct;
  160 }
  161 
  162 
  163 /****************************************************************************
  164  *
  165  * Function: DisplayBanner()
  166  *
  167  * Purpose:  Show valuable proggie info
  168  *
  169  * Arguments: None.
  170  *
  171  * Returns: 0 all the time
  172  *
  173  ****************************************************************************/
  174 int DisplayBanner(void)
  175 {
  176     const char * info;
  177     const char * pcre_ver;
  178     const char * zlib_ver;
  179 
  180     info = getenv("HOSTTYPE");
  181     if( !info )
  182     {
  183         info="";
  184     }
  185 
  186     pcre_ver = pcre_version();
  187     zlib_ver = zlib_version;
  188 
  189     LogMessage("\n");
  190     LogMessage("   ,,_     -*> Snort! <*-\n");
  191     LogMessage("  o\"  )~   Version %s%s (Build %s) %s\n",
  192                VERSION,
  193 #ifdef GRE
  194                " GRE",
  195 #else
  196                "",
  197 #endif
  198                BUILD,
  199                info);
  200     LogMessage("   ''''    By Martin Roesch & The Snort Team: http://www.snort.org/contact#team\n");
  201     LogMessage("           Copyright (C) 2014-2020 Cisco and/or its affiliates. All rights reserved.\n");
  202     LogMessage("           Copyright (C) 1998-2013 Sourcefire, Inc., et al.\n");
  203 #ifdef HAVE_PCAP_LIB_VERSION
  204     LogMessage("           Using %s\n", pcap_lib_version());
  205 #endif
  206     LogMessage("           Using PCRE version: %s\n", pcre_ver);
  207     LogMessage("           Using ZLIB version: %s\n", zlib_ver);
  208     LogMessage("\n");
  209 
  210     return 0;
  211 }
  212 
  213 
  214 
  215 /****************************************************************************
  216  *
  217  * Function: ts_print(register const struct, char *)
  218  *
  219  * Purpose: Generate a time stamp and stuff it in a buffer.  This one has
  220  *          millisecond precision.  Oh yeah, I ripped this code off from
  221  *          TCPdump, props to those guys.
  222  *
  223  * Arguments: timeval => clock struct coming out of libpcap
  224  *            timebuf => buffer to stuff timestamp into
  225  *
  226  * Returns: void function
  227  *
  228  ****************************************************************************/
  229 void ts_print(register const struct timeval *tvp, char *timebuf)
  230 {
  231     register int s;
  232     int    localzone;
  233     time_t Time;
  234     struct timeval tv;
  235     struct timezone tz;
  236     struct tm *lt;    /* place to stick the adjusted clock data */
  237 
  238     /* if null was passed, we use current time */
  239     if(!tvp)
  240     {
  241         /* manual page (for linux) says tz is never used, so.. */
  242         memset((char *) &tz, 0, sizeof(tz));
  243         gettimeofday(&tv, &tz);
  244         tvp = &tv;
  245     }
  246 
  247     localzone = snort_conf->thiszone;
  248 
  249     /*
  250     **  If we're doing UTC, then make sure that the timezone is correct.
  251     */
  252     if (ScOutputUseUtc())
  253         localzone = 0;
  254 
  255     s = (tvp->tv_sec + localzone) % 86400;
  256     Time = (tvp->tv_sec + localzone) - s;
  257 
  258     lt = gmtime(&Time);
  259 
  260     if(!lt)
  261     {
  262          /* Invalid time, set to 0*/
  263          s = 0;
  264          Time = 0;
  265          lt = gmtime(&Time);
  266     }
  267 
  268     if (ScOutputIncludeYear())
  269     {
  270         int year = (lt->tm_year >= 100) ? (lt->tm_year - 100) : lt->tm_year;
  271         (void) SnortSnprintf(timebuf, TIMEBUF_SIZE,
  272                         "%02d/%02d/%02d-%02d:%02d:%02d.%06u ",
  273                         lt->tm_mon + 1, lt->tm_mday, year,
  274                         s / 3600, (s % 3600) / 60, s % 60,
  275                         (u_int) tvp->tv_usec);
  276     }
  277     else
  278     {
  279         (void) SnortSnprintf(timebuf, TIMEBUF_SIZE,
  280                         "%02d/%02d-%02d:%02d:%02d.%06u ", lt->tm_mon + 1,
  281                         lt->tm_mday, s / 3600, (s % 3600) / 60, s % 60,
  282                         (u_int) tvp->tv_usec);
  283     }
  284 }
  285 
  286 
  287 
  288 /****************************************************************************
  289  *
  290  * Function: gmt2local(time_t)
  291  *
  292  * Purpose: Figures out how to adjust the current clock reading based on the
  293  *          timezone you're in.  Ripped off from TCPdump.
  294  *
  295  * Arguments: time_t => offset from GMT
  296  *
  297  * Returns: offset seconds from GMT
  298  *
  299  ****************************************************************************/
  300 int gmt2local(time_t t)
  301 {
  302     register int dt, dir;
  303     register struct tm *gmt, *loc;
  304     struct tm sgmt;
  305 
  306     if(t == 0)
  307         t = time(NULL);
  308 
  309     gmt = &sgmt;
  310     *gmt = *gmtime(&t);
  311     loc = localtime(&t);
  312 
  313     dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 +
  314         (loc->tm_min - gmt->tm_min) * 60;
  315 
  316     dir = loc->tm_year - gmt->tm_year;
  317 
  318     if(dir == 0)
  319         dir = loc->tm_yday - gmt->tm_yday;
  320 
  321     dt += dir * 24 * 60 * 60;
  322 
  323     return(dt);
  324 }
  325 
  326 
  327 
  328 
  329 /****************************************************************************
  330  *
  331  * Function: copy_argv(u_char **)
  332  *
  333  * Purpose: Copies a 2D array (like argv) into a flat string.  Stolen from
  334  *          TCPDump.
  335  *
  336  * Arguments: argv => 2D array to flatten
  337  *
  338  * Returns: Pointer to the flat string
  339  *
  340  ****************************************************************************/
  341 char *copy_argv(char **argv)
  342 {
  343     char **p;
  344     u_int len = 0;
  345     char *buf;
  346     char *src, *dst;
  347     //void ftlerr(char *,...);
  348 
  349     p = argv;
  350     if(*p == 0)
  351         return 0;
  352 
  353     while(*p)
  354         len += strlen(*p++) + 1;
  355 
  356     buf = (char *) calloc(1,len);
  357 
  358     if(buf == NULL)
  359     {
  360         FatalError("calloc() failed: %s\n", strerror(errno));
  361     }
  362     p = argv;
  363     dst = buf;
  364 
  365     while((src = *p++) != NULL)
  366     {
  367         while((*dst++ = *src++) != '\0');
  368         dst[-1] = ' ';
  369     }
  370 
  371     dst[-1] = '\0';
  372 
  373     /* Check for an empty string */
  374     dst = buf;
  375     while (isspace((int)*dst))
  376         dst++;
  377 
  378     if (strlen(dst) == 0)
  379     {
  380         free(buf);
  381         buf = NULL;
  382     }
  383 
  384     return buf;
  385 }
  386 
  387 
  388 /****************************************************************************
  389  *
  390  * Function: strip(char *)
  391  *
  392  * Purpose: Strips a data buffer of CR/LF/TABs.  Replaces CR/LF's with
  393  *          NULL and TABs with spaces.
  394  *
  395  * Arguments: data => ptr to the data buf to be stripped
  396  *
  397  * Returns: void
  398  *
  399  * 3/7/07 - changed to return void - use strlen to get size of string
  400  *
  401  * Note that this function will turn all '\n' and '\r' into null chars
  402  * so, e.g. 'Hello\nWorld\n' => 'Hello\x00World\x00'
  403  * note that the string is now just 'Hello' and the length is shortened
  404  * by more than just an ending '\n' or '\r'
  405  ****************************************************************************/
  406 void strip(char *data)
  407 {
  408     int size;
  409     char *end;
  410     char *idx;
  411 
  412     idx = data;
  413     end = data + strlen(data);
  414     size = end - idx;
  415 
  416     while(idx != end)
  417     {
  418         if((*idx == '\n') ||
  419                 (*idx == '\r'))
  420         {
  421             *idx = 0;
  422             size--;
  423         }
  424         if(*idx == '\t')
  425         {
  426             *idx = ' ';
  427         }
  428         idx++;
  429     }
  430 }
  431 
  432 /*
  433  * Function: ErrorMessage(const char *, ...)
  434  *
  435  * Purpose: Print a message to stderr.
  436  *
  437  * Arguments: format => the formatted error string to print out
  438  *            ... => format commands/fillers
  439  *
  440  * Returns: void function
  441  */
  442 void ErrorMessage(const char *format,...)
  443 {
  444     char buf[STD_BUF+1];
  445     va_list ap;
  446 
  447     if (snort_conf == NULL)
  448         return;
  449 
  450     va_start(ap, format);
  451 
  452     if (ScDaemonMode() || ScLogSyslog())
  453     {
  454         vsnprintf(buf, STD_BUF, format, ap);
  455         buf[STD_BUF] = '\0';
  456         syslog(LOG_CONS | LOG_DAEMON | LOG_ERR, "%s", buf);
  457     }
  458     else
  459     {
  460         vfprintf(stderr, format, ap);
  461     }
  462     va_end(ap);
  463 }
  464 
  465 /*
  466  * Function: ErrorMessageThrottled(ThrottleInfo *,const char *, ...)
  467  *
  468  * Purpose: Print a message to stderr, and throttle when
  469  *          too many messages are printed.
  470  *
  471  * Arguments: throttleInfo => point to the saved throttle state information
  472  *            format => the formatted error string to print out
  473  *            ... => format commands/fillers
  474  *
  475  * Returns: void function
  476  */
  477 
  478 void ErrorMessageThrottled(ThrottleInfo *throttleInfo, const char *format,...)
  479 {
  480     char buf[STD_BUF+1];
  481     va_list ap;
  482     time_t current_time = packet_time();
  483 
  484     if ((snort_conf == NULL)||(!throttleInfo))
  485         return;
  486 
  487     if (!ScCheckInternalLogLevel(INTERNAL_LOG_LEVEL__ERROR))
  488         return;
  489 
  490     throttleInfo->count++;
  491     DEBUG_WRAP(DebugMessage(DEBUG_INIT,"current_time: %d, throttle (%p): count "STDu64", last update: %d\n",
  492             (int)current_time, throttleInfo, throttleInfo->count, (int)throttleInfo->lastUpdate );)
  493     /*Note: we only output the first error message,
  494      * and the statistics after at least duration_to_log seconds
  495      * when the same type of error message is printed out again */
  496     if (current_time - (time_t)throttleInfo->duration_to_log > throttleInfo->lastUpdate)
  497     {
  498         int index;
  499         va_start(ap, format);
  500         index = vsnprintf(buf, STD_BUF, format, ap);
  501         va_end(ap);
  502 
  503         if (index && (throttleInfo->count > 1))
  504         {
  505            snprintf(&buf[index - 1], STD_BUF-index,
  506                    " (suppressed "STDu64" times in the last %d seconds).\n",
  507                    throttleInfo->count, (int) (current_time - throttleInfo->lastUpdate));
  508         }
  509 
  510         ErrorMessage("%s",buf);
  511         throttleInfo->lastUpdate = current_time;
  512         throttleInfo->count = 0;
  513     }
  514 
  515 }
  516 
  517 /*
  518  * Function: LogThrottledByTimeCount(ThrottleInfo *,const char *, ...)
  519  *   
  520  * Purpose: Print a message based on time and count of messages.
  521  *      
  522  * Arguments: throttleInfo => point to the saved throttle state information
  523  *            format => the formatted message string to print out
  524  *            ... => format commands/fillers
  525  *          
  526  * Returns: void function
  527  */            
  528 void LogThrottledByTimeCount(ThrottleInfo *throttleInfo, const char *format,...)
  529 {
  530     char buf[STD_BUF+1];
  531     va_list ap;
  532     time_t current_time = packet_time();
  533 
  534     if ((!snort_conf) || (!throttleInfo))
  535         return;
  536 
  537     if (!ScCheckInternalLogLevel(INTERNAL_LOG_LEVEL__ERROR))
  538         return;
  539 
  540     throttleInfo->count++;
  541     DEBUG_WRAP(DebugMessage(DEBUG_INIT,"current_time: %d, throttle (%p): count "STDu64", last update: %d\n",
  542                 (int)current_time, throttleInfo, throttleInfo->count, (int)throttleInfo->lastUpdate );)
  543 
  544     if ((throttleInfo->lastUpdate == 0)
  545            || ((current_time - (time_t)throttleInfo->duration_to_log > throttleInfo->lastUpdate)
  546            && ((throttleInfo->count == 1)
  547            || throttleInfo->count > throttleInfo->count_to_log)))
  548     {
  549        int index;
  550        va_start(ap, format);
  551        index = vsnprintf(buf, STD_BUF, format, ap);
  552        va_end(ap);
  553 
  554        if (index) 
  555        {
  556            snprintf(&buf[index - 1], STD_BUF-index,
  557                " (suppressed "STDu64" times in the last %d seconds).\n",
  558                throttleInfo->count, throttleInfo->lastUpdate
  559                ? ((int)(current_time - throttleInfo->lastUpdate))
  560                : ((int)throttleInfo->lastUpdate));
  561        }
  562 
  563        LogMessage("%s",buf);
  564        throttleInfo->lastUpdate = current_time;
  565        throttleInfo->count = 0;
  566     }
  567 }
  568 
  569 /*
  570  * Function: LogMessage(const char *, ...)
  571  *
  572  * Purpose: Print a message to stderr or with logfacility.
  573  *
  574  * Arguments: format => the formatted error string to print out
  575  *            ... => format commands/fillers
  576  *
  577  * Returns: void function
  578  */
  579 void LogMessage(const char *format,...)
  580 {
  581     char buf[STD_BUF+1];
  582     va_list ap;
  583 
  584     if (snort_conf == NULL)
  585         return;
  586 
  587     if (!ScCheckInternalLogLevel(INTERNAL_LOG_LEVEL__MESSAGE))
  588         return;
  589 
  590     va_start(ap, format);
  591 
  592     if (ScDaemonMode() || ScLogSyslog())
  593     {
  594         vsnprintf(buf, STD_BUF, format, ap);
  595         buf[STD_BUF] = '\0';
  596         syslog(LOG_DAEMON | LOG_NOTICE, "%s", buf);
  597     }
  598     else
  599     {
  600         vfprintf(stderr, format, ap);
  601     }
  602 
  603     va_end(ap);
  604 }
  605 
  606 /*
  607  * Function: WarningMessage(const char *, ...)
  608  *
  609  * Purpose: Print a message to stderr or with logfacility.
  610  *
  611  * Arguments: format => the formatted error string to print out
  612  *            ... => format commands/fillers
  613  *
  614  * Returns: void function
  615  */
  616 void WarningMessage(const char *format,...)
  617 {
  618     char buf[STD_BUF+1];
  619     va_list ap;
  620 
  621     if (snort_conf == NULL)
  622         return;
  623 
  624     if (!ScCheckInternalLogLevel(INTERNAL_LOG_LEVEL__WARNING))
  625         return;
  626 
  627     va_start(ap, format);
  628 
  629     if (ScDaemonMode() || ScLogSyslog())
  630     {
  631         vsnprintf(buf, STD_BUF, format, ap);
  632         buf[STD_BUF] = '\0';
  633         syslog(LOG_DAEMON | LOG_WARNING, "%s", buf);
  634     }
  635     else
  636     {
  637         vfprintf(stderr, format, ap);
  638     }
  639 
  640     va_end(ap);
  641 }
  642 
  643 /*
  644  * Function: CreateApplicationEventLogEntry(const char *)
  645  *
  646  * Purpose: Add an entry to the Win32 "Application" EventLog
  647  *
  648  * Arguments: szMessage => the formatted error string to print out
  649  *
  650  * Returns: void function
  651  */
  652 #if defined(WIN32) && defined(ENABLE_WIN32_SERVICE)
  653 void CreateApplicationEventLogEntry(const char *msg)
  654 {
  655     HANDLE hEventLog;
  656     char*  pEventSourceName = "SnortService";
  657 
  658     /* prepare to write to Application log on local host
  659       * with Event Source of SnortService
  660       */
  661     AddEventSource(pEventSourceName);
  662     hEventLog = RegisterEventSource(NULL, pEventSourceName);
  663     if (hEventLog == NULL)
  664     {
  665         /* Could not register the event source. */
  666         return;
  667     }
  668 
  669     if (!ReportEvent(hEventLog,   /* event log handle               */
  670             EVENTLOG_ERROR_TYPE,  /* event type                     */
  671             0,                    /* category zero                  */
  672             EVMSG_SIMPLE,         /* event identifier               */
  673             NULL,                 /* no user security identifier    */
  674             1,                    /* one substitution string        */
  675             0,                    /* no data                        */
  676             &msg,                 /* pointer to array of strings    */
  677             NULL))                /* pointer to data                */
  678     {
  679         /* Could not report the event. */
  680     }
  681 
  682     DeregisterEventSource(hEventLog);
  683 }
  684 #endif  /* WIN32 && ENABLE_WIN32_SERVICE */
  685 
  686 
  687 static int already_fatal = 0;
  688 
  689 /*
  690  * Function: SnortFatalExit(void)
  691  *
  692  * Purpose: When a fatal error occurs, this function cleanly
  693  *          shuts down the program
  694  *
  695  * Arguments: none
  696  *
  697  * Returns: void function
  698  */
  699 NORETURN void SnortFatalExit(void)
  700 {
  701     // -----------------------------
  702     // bail now if we are reentering
  703     if ( already_fatal )
  704         exit(1);
  705     else
  706         already_fatal = 1;
  707 
  708     if (!snort_conf || (!ScDaemonMode() && !ScLogSyslog()))
  709         fprintf(stderr,"Fatal Error, Quitting..\n");
  710 
  711     if ( InMainThread() || SnortIsInitializing() )
  712     {
  713         DAQ_Abort();
  714         exit(1);
  715     }
  716     else
  717     {
  718         DAQ_BreakLoop(1);
  719 #ifndef WIN32
  720         pthread_exit(NULL);
  721 #endif
  722     }
  723 }
  724 
  725 /*
  726  * Function: FatalError(const char *, ...)
  727  *
  728  * Purpose: When a fatal error occurs, this function prints the error message
  729  *          and cleanly shuts down the program
  730  *
  731  * Arguments: format => the formatted error string to print out
  732  *            ... => format commands/fillers
  733  *
  734  * Returns: void function
  735  */
  736 NORETURN void FatalError(const char *format,...)
  737 {
  738     char buf[STD_BUF+1];
  739     va_list ap;
  740 
  741     // -----------------------------
  742     // bail now if we are reentering
  743     if ( already_fatal )
  744         exit(1);
  745     else
  746         already_fatal = 1;
  747     // -----------------------------
  748 
  749     va_start(ap, format);
  750     vsnprintf(buf, STD_BUF, format, ap);
  751     va_end(ap);
  752 
  753     buf[STD_BUF] = '\0';
  754 
  755     if ((snort_conf != NULL) && (ScDaemonMode() || ScLogSyslog()))
  756     {
  757         syslog(LOG_CONS | LOG_DAEMON | LOG_ERR, "FATAL ERROR: %s", buf);
  758     }
  759     else
  760     {
  761         fprintf(stderr, "ERROR: %s", buf);
  762         fprintf(stderr,"Fatal Error, Quitting..\n");
  763 #if defined(WIN32) && defined(ENABLE_WIN32_SERVICE)
  764         CreateApplicationEventLogEntry(buf);
  765 #endif
  766     }
  767 
  768     if ( InMainThread() || SnortIsInitializing() )
  769     {
  770         if (!SnortIsInitializing()) 
  771         {
  772             /*
  773              * Shutdown the thread only when the snort is not 
  774              * initializing. Because FatalError api can be 
  775              * called during initialization as well.
  776              */
  777             SnortShutdownThreads(1);
  778         }
  779         DAQ_Abort();
  780         exit(1);
  781     }
  782     else
  783     {
  784         DAQ_BreakLoop(1);
  785 #ifndef WIN32
  786         pthread_exit(NULL);
  787 #endif
  788     }
  789 }
  790 
  791 
  792 /****************************************************************************
  793  *
  794  * Function: CreatePidFile(char *)
  795  *
  796  * Purpose:  Creates a PID file
  797  *
  798  * Arguments: Interface opened.
  799  *
  800  * Returns: void function
  801  *
  802  ****************************************************************************/
  803 static FILE *pid_lockfile = NULL;
  804 static FILE *pid_file = NULL;
  805 
  806 void CreatePidFile(const char *intf, pid_t pid)
  807 {
  808     struct stat pt;
  809 #ifdef WIN32
  810     char dir[STD_BUF + 1];
  811 #endif
  812 
  813     if (!ScReadMode())
  814     {
  815         LogMessage("Checking PID path...\n");
  816 
  817         if (strlen(snort_conf->pid_path) != 0)
  818         {
  819             if((stat(snort_conf->pid_path, &pt) == -1) ||
  820                 !S_ISDIR(pt.st_mode) || access(snort_conf->pid_path, W_OK) == -1)
  821             {
  822 #ifndef WIN32
  823                 /* Save this just in case it's reset with LogMessage call */
  824                 int err = errno;
  825 
  826                 LogMessage("WARNING: %s is invalid, trying "
  827                            "/var/run...\n", snort_conf->pid_path);
  828                 if (err)
  829                 {
  830                     LogMessage("Previous Error, errno=%d, (%s)\n",
  831                                err, strerror(err) == NULL ? "Unknown error" : strerror(err));
  832                 }
  833 #endif
  834                 memset(snort_conf->pid_path, 0, sizeof(snort_conf->pid_path));
  835             }
  836             else
  837             {
  838                 LogMessage("PID path stat checked out ok, "
  839                            "PID path set to %s\n", snort_conf->pid_path);
  840             }
  841         }
  842 
  843         if (strlen(snort_conf->pid_path) == 0)
  844         {
  845 #ifndef _PATH_VARRUN
  846 # ifndef WIN32
  847             SnortStrncpy(_PATH_VARRUN, "/var/run/", sizeof(_PATH_VARRUN));
  848 # else
  849             if (GetCurrentDirectory(sizeof(dir) - 1, dir))
  850                 SnortStrncpy(_PATH_VARRUN, dir, sizeof(_PATH_VARRUN));
  851 # endif  /* WIN32 */
  852 #else
  853             LogMessage("PATH_VARRUN is set to %s on this operating "
  854                        "system\n", _PATH_VARRUN);
  855 #endif  /* _PATH_VARRUN */
  856 
  857             if ((stat(_PATH_VARRUN, &pt) == -1) ||
  858                 !S_ISDIR(pt.st_mode) || access(_PATH_VARRUN, W_OK) == -1)
  859             {
  860                 LogMessage("WARNING: _PATH_VARRUN is invalid, trying "
  861                            "/var/log/ ...\n");
  862                 SnortStrncpy(snort_conf->pid_path, "/var/log/", sizeof(snort_conf->pid_path));
  863                 if ((stat(snort_conf->pid_path, &pt) == -1) ||
  864                     !S_ISDIR(pt.st_mode) || access(snort_conf->pid_path, W_OK) == -1)
  865                 {
  866                     LogMessage("WARNING: %s is invalid, logging Snort "
  867                                "PID path to log directory (%s).\n", snort_conf->pid_path,
  868                                snort_conf->log_dir);
  869                     CheckLogDir();
  870                     SnortSnprintf(snort_conf->pid_path, sizeof(snort_conf->pid_path),
  871                                   "%s/", snort_conf->log_dir);
  872                 }
  873             }
  874             else
  875             {
  876                 LogMessage("PID path stat checked out ok, "
  877                            "PID path set to %s\n", _PATH_VARRUN);
  878                 SnortStrncpy(snort_conf->pid_path, _PATH_VARRUN, sizeof(snort_conf->pid_path));
  879             }
  880         }
  881     }
  882 
  883     if(intf == NULL || strlen(snort_conf->pid_path) == 0)
  884     {
  885         /* snort_conf->pid_path should have some value by now
  886          * so let us just be sane. */
  887         FatalError("CreatePidFile() failed to lookup interface or pid_path is unknown!\n");
  888     }
  889 
  890     if (ScNoInterfacePidFile())
  891     {
  892         SnortSnprintf(snort_conf->pid_filename, sizeof(snort_conf->pid_filename),
  893                   "%s/snort%s.pid", snort_conf->pid_path, snort_conf->pidfile_suffix);
  894     }
  895     else
  896     {
  897         SnortSnprintf(snort_conf->pid_filename, sizeof(snort_conf->pid_filename),
  898                   "%s/snort_%s%s.pid", snort_conf->pid_path, intf, snort_conf->pidfile_suffix);
  899     }
  900 
  901 #ifndef WIN32
  902     if (!ScNoLockPidFile())
  903     {
  904         char pid_lockfilename[STD_BUF+1];
  905         int lock_fd;
  906 
  907         /* First, lock the PID file */
  908         SnortSnprintf(pid_lockfilename, STD_BUF, "%s.lck", snort_conf->pid_filename);
  909         pid_lockfile = fopen(pid_lockfilename, "w");
  910 
  911         if (pid_lockfile)
  912         {
  913             struct flock lock;
  914             lock_fd = fileno(pid_lockfile);
  915 
  916             lock.l_type = F_WRLCK;
  917             lock.l_whence = SEEK_SET;
  918             lock.l_start = 0;
  919             lock.l_len = 0;
  920 
  921             if (fcntl(lock_fd, F_SETLK, &lock) == -1)
  922             {
  923                 ClosePidFile();
  924                 FatalError("Failed to Lock PID File \"%s\" for PID \"%d\"\n", snort_conf->pid_filename, (int)pid);
  925             }
  926 
  927             /* Give desired user control over lock file */
  928             fchown(fileno(pid_lockfile), ScUid(), ScGid());
  929         }
  930     }
  931 #endif
  932 
  933     /* Okay, were able to lock PID file, now open and write PID */
  934     pid_file = fopen(snort_conf->pid_filename, "w");
  935     if(pid_file)
  936     {
  937         LogMessage("Writing PID \"%d\" to file \"%s\"\n", (int)pid, snort_conf->pid_filename);
  938         fprintf(pid_file, "%d\n", (int)pid);
  939         fflush(pid_file);
  940         
  941 #ifndef WIN32
  942         /* Give desired user control over pid file */
  943         fchown(fileno(pid_file), ScUid(), ScGid());
  944 #endif
  945     }
  946     else
  947     {
  948         char errBuf[STD_BUF];
  949 #ifdef WIN32
  950         SnortSnprintf(errBuf, STD_BUF, "%s", strerror(errno));
  951 #else
  952         strerror_r(errno, errBuf, STD_BUF);
  953 #endif
  954         ErrorMessage("Failed to create pid file %s, Error: %s", snort_conf->pid_filename, errBuf);
  955         snort_conf->pid_filename[0] = 0;
  956     }
  957 }
  958 
  959 /****************************************************************************
  960  *
  961  * Function: ClosePidFile(char *)
  962  *
  963  * Purpose:  Releases lock on a PID file
  964  *
  965  * Arguments: None
  966  *
  967  * Returns: void function
  968  *
  969  ****************************************************************************/
  970 void ClosePidFile(void)
  971 {
  972     if (pid_file)
  973     {
  974         fclose(pid_file);
  975         pid_file = NULL;
  976     }
  977     if (pid_lockfile)
  978     {
  979         fclose(pid_lockfile);
  980         pid_lockfile = NULL;
  981     }
  982 }
  983 
  984 /****************************************************************************
  985  *
  986  * Function: SetUidGid()
  987  *
  988  * Purpose:  Sets safe UserID and GroupID if needed
  989  *
  990  * Arguments: none
  991  *
  992  * Returns: void function
  993  *
  994  ****************************************************************************/
  995 void SetUidGid(int user_id, int group_id)
  996 {
  997 #ifndef WIN32
  998 
  999     if ((group_id != -1) && (getgid() != (gid_t)group_id))
 1000     {
 1001         if ( !DAQ_Unprivileged() )
 1002         {
 1003             LogMessage("WARNING: cannot set uid and gid - %s DAQ does not"
 1004                 " support unprivileged operation.\n", DAQ_GetType());
 1005             return;
 1006         }
 1007 
 1008         if (setgid(group_id) < 0)
 1009             FatalError("Cannot set gid: %d\n", group_id);
 1010 
 1011         LogMessage("Set gid to %d\n", group_id);
 1012     }
 1013 
 1014     if ((user_id != -1) && (getuid() != (uid_t)user_id))
 1015     {
 1016         if ( !DAQ_Unprivileged() )
 1017         {
 1018             LogMessage("WARNING: cannot set uid and gid - %s DAQ does not"
 1019                 " support unprivileged operation.\n", DAQ_GetType());
 1020             return;
 1021         }
 1022 
 1023         if (setuid(user_id) < 0)
 1024             FatalError("Can not set uid: %d\n", user_id);
 1025 
 1026         LogMessage("Set uid to %d\n", user_id);
 1027     }
 1028 #endif  /* WIN32 */
 1029 }
 1030 
 1031 /****************************************************************************
 1032  *
 1033  * Function: InitGroups()
 1034  *
 1035  * Purpose:  Sets the groups of the process based on the UserID with the
 1036  *           GroupID added
 1037  *
 1038  * Arguments: none
 1039  *
 1040  * Returns: void function
 1041  *
 1042  ****************************************************************************/
 1043 void InitGroups(int user_id, int group_id)
 1044 {
 1045 #ifndef WIN32
 1046 
 1047     if ((user_id != -1) && (getuid() == 0))
 1048     {
 1049         struct passwd *pw = getpwuid(user_id);
 1050 
 1051         if (pw != NULL)
 1052         {
 1053             /* getpwuid and initgroups may use the same static buffers */
 1054             char *username = SnortStrdup(pw->pw_name);
 1055 
 1056             if (initgroups(username, group_id) < 0)
 1057             {
 1058                 free(username);
 1059                 FatalError("Can not initgroups(%s,%d)", username, group_id);
 1060             }
 1061 
 1062             free(username);
 1063         }
 1064 
 1065         /** Just to be on the safe side... **/
 1066         endgrent();
 1067         endpwent();
 1068     }
 1069 #endif  /* WIN32 */
 1070 }
 1071 
 1072 //-------------------------------------------------------------------------
 1073 
 1074 #define STATS_SEPARATOR \
 1075     "==============================================================================="
 1076 
 1077 static inline int DisplayCount (char *buf, const char* s, uint64_t n, int size)
 1078 {
 1079     return snprintf(buf+size, CS_STATS_BUF_SIZE-size, "%11s: " FMTu64("12") "\n", s, n);
 1080 }
 1081 
 1082 static inline int DisplayStat (char *buf, const char* s, uint64_t n, uint64_t tot, int size)
 1083 {
 1084     return snprintf(buf+size, CS_STATS_BUF_SIZE-size,
 1085         "%11s: " FMTu64("12") " (%7.3f%%)\n",
 1086         s, n, CalcPct(n, tot));
 1087 }
 1088 
 1089 static inline void LogCount (const char* s, uint64_t n)
 1090 {
 1091     LogMessage("%11s: " FMTu64("12") "\n", s, n);
 1092 }
 1093 
 1094 static inline void LogStat (const char* s, uint64_t n, uint64_t tot)
 1095 {
 1096     LogMessage(
 1097         "%11s: " FMTu64("12") " (%7.3f%%)\n",
 1098         s, n, CalcPct(n, tot));
 1099 }
 1100 
 1101 static struct timeval starttime;
 1102 
 1103 void TimeStart (void)
 1104 {
 1105     gettimeofday(&starttime, NULL);
 1106 }
 1107 
 1108 void TimeStop (void)
 1109 {
 1110     uint32_t days = 0, hrs = 0, mins = 0, secs = 0;
 1111     uint32_t total_secs = 0, tmp = 0;
 1112     uint64_t pps = 0;
 1113 
 1114     struct timeval endtime, difftime;
 1115     gettimeofday(&endtime, NULL);
 1116     TIMERSUB(&endtime, &starttime, &difftime);
 1117 
 1118     LogMessage("%s\n", STATS_SEPARATOR);
 1119 
 1120     LogMessage("Run time for packet processing was %lu.%lu seconds\n",
 1121         (unsigned long)difftime.tv_sec, (unsigned long)difftime.tv_usec);
 1122 
 1123     LogMessage("Snort processed " STDu64 " packets.\n", pc.total_from_daq);
 1124 
 1125     tmp = total_secs = (uint32_t)difftime.tv_sec;
 1126     if ( total_secs < 1 ) total_secs = 1;
 1127 
 1128     days = tmp / SECONDS_PER_DAY;
 1129     tmp  = tmp % SECONDS_PER_DAY;
 1130 
 1131     hrs  = tmp / SECONDS_PER_HOUR;
 1132     tmp  = tmp % SECONDS_PER_HOUR;
 1133 
 1134     mins = tmp / SECONDS_PER_MIN;
 1135     secs = tmp % SECONDS_PER_MIN;
 1136 
 1137     LogMessage("Snort ran for %u days %u hours %u minutes %u seconds\n",
 1138                  days, hrs, mins, secs);
 1139 
 1140     if ( days > 0 )
 1141     {
 1142         uint64_t n = (pc.total_from_daq / (total_secs / SECONDS_PER_DAY));
 1143         LogCount("Pkts/day", n);
 1144     }
 1145 
 1146     if ( hrs > 0 || days > 0 )
 1147     {
 1148         uint64_t n = (pc.total_from_daq / (total_secs / SECONDS_PER_HOUR));
 1149         LogCount("Pkts/hr", n);
 1150     }
 1151 
 1152     if ( mins > 0 || hrs > 0 || days > 0 )
 1153     {
 1154         uint64_t n = (pc.total_from_daq / (total_secs / SECONDS_PER_MIN));
 1155         LogCount("Pkts/min", n);
 1156     }
 1157 
 1158     pps = (pc.total_from_daq / total_secs);
 1159     LogCount("Pkts/sec", pps);
 1160 }
 1161 
 1162 //-------------------------------------------------------------------------
 1163 
 1164 static const char* Verdicts[MAX_DAQ_VERDICT] = {
 1165     "Allow",
 1166     "Block",
 1167     "Replace",
 1168     "Whitelist",
 1169     "Blacklist",
 1170 #ifdef HAVE_DAQ_VERDICT_RETRY
 1171     "Ignore",
 1172     "Retry"
 1173 #else
 1174     "Ignore"
 1175 #endif
 1176 };
 1177 
 1178 #ifdef HAVE_MALLINFO
 1179 static void display_mallinfo(void)
 1180 {
 1181     mi = mallinfo();
 1182     LogMessage("%s\n", STATS_SEPARATOR);
 1183     LogMessage("Memory usage summary:\n");
 1184     LogMessage("  Total non-mmapped bytes (arena):       %d\n", mi.arena);
 1185     LogMessage("  Bytes in mapped regions (hblkhd):      %d\n", mi.hblkhd);
 1186     LogMessage("  Total allocated space (uordblks):      %d\n", mi.uordblks);
 1187     LogMessage("  Total free space (fordblks):           %d\n", mi.fordblks);
 1188     LogMessage("  Topmost releasable block (keepcost):   %d\n", mi.keepcost);
 1189 #ifdef DEBUG
 1190     LogMessage("  Number of free chunks (ordblks):       %d\n", mi.ordblks);
 1191     LogMessage("  Number of free fastbin blocks (smblks):%d\n", mi.smblks);
 1192     LogMessage("  Number of mapped regions (hblks):      %d\n", mi.hblks);
 1193     LogMessage("  Max. total allocated space (usmblks):  %d\n", mi.usmblks);
 1194     LogMessage("  Free bytes held in fastbins (fsmblks): %d\n", mi.fsmblks);
 1195 #endif
 1196 
 1197 }
 1198 #endif
 1199 
 1200 void DisplayActionStats (uint16_t type, void *old_context, struct _THREAD_ELEMENT *te, ControlDataSendFunc f)
 1201 {
 1202     char buffer[CS_STATS_BUF_SIZE + 1];
 1203     int len = 0;
 1204     int i = 0;
 1205     uint64_t total = pc.total_processed;
 1206     uint64_t pkts_recv = pc.total_from_daq;
 1207     const DAQ_Stats_t* pkt_stats = DAQ_GetStats();
 1208 
 1209     if (total) {
 1210         // ensure proper counting of log_limit
 1211         SnortEventqResetCounts();
 1212 
 1213         len += snprintf(buffer, CS_STATS_BUF_SIZE,  "Action Stats:\n");
 1214         len += DisplayStat(buffer, "Alerts", pc.total_alert_pkts, total, len);
 1215         len += DisplayStat(buffer, "Logged", pc.log_pkts, total, len);
 1216         len += DisplayStat(buffer, "Passed", pc.pass_pkts, total, len);
 1217         len += snprintf(buffer+len, CS_STATS_BUF_SIZE-len,  "Limits:\n");
 1218         len += DisplayCount(buffer, "Match", pc.match_limit, len);
 1219         len += DisplayCount(buffer, "Queue", pc.queue_limit, len);
 1220         len += DisplayCount(buffer, "Log", pc.log_limit, len);
 1221         len += DisplayCount(buffer, "Event", pc.event_limit, len);
 1222         len += DisplayCount(buffer, "Alert", pc.alert_limit, len);
 1223         len += snprintf(buffer+len, CS_STATS_BUF_SIZE-len,  "Verdicts:\n");
 1224 
 1225         for ( i = 0; i < MAX_DAQ_VERDICT && len < CS_STATS_BUF_SIZE; i++ ) {
 1226             const char* s = Verdicts[i];
 1227             len += DisplayStat(buffer, s, pkt_stats->verdicts[i], pkts_recv, len);
 1228         }
 1229         if ( pc.internal_blacklist )
 1230             len += DisplayStat(buffer, "Int Blklst", pc.internal_blacklist, pkts_recv, len);
 1231 
 1232         if ( pc.internal_whitelist )
 1233             len += DisplayStat(buffer, "Int Whtlst", pc.internal_whitelist, pkts_recv, len);
 1234     } else {
 1235         len = snprintf(buffer, CS_STATS_BUF_SIZE,  "Action Stats are not available\n Total Action Processed:"FMTu64("12") "\n", total);
 1236     }
 1237 
 1238     if (-1 == f(te, (const uint8_t *)buffer, len)) {
 1239         LogMessage("Unable to send data to the frontend\n");
 1240     }
 1241 }
 1242 
 1243 /* exiting should be 0 for if not exiting, 1 if restarting, and 2 if exiting */
 1244 void DropStats(int exiting)
 1245 {
 1246     PreprocStatsFuncNode *idx;
 1247     uint64_t total = pc.total_processed;
 1248     uint64_t pkts_recv = pc.total_from_daq;
 1249 
 1250     const DAQ_Stats_t* pkt_stats = DAQ_GetStats();
 1251 
 1252     /*Display all the memory usage in main arena*/
 1253 #ifdef HAVE_MALLINFO
 1254     display_mallinfo();
 1255 #endif
 1256 
 1257 #ifdef PPM_MGR
 1258     PPM_PRINT_SUMMARY(&snort_conf->ppm_cfg);
 1259 #endif
 1260 
 1261     {
 1262         uint64_t pkts_drop, pkts_out, pkts_inj;
 1263 
 1264         pkts_recv = pkt_stats->hw_packets_received;
 1265         pkts_drop = pkt_stats->hw_packets_dropped;
 1266 
 1267         if ( pkts_recv > pkt_stats->packets_filtered
 1268                        + pkt_stats->packets_received )
 1269             pkts_out = pkts_recv - pkt_stats->packets_filtered
 1270                      - pkt_stats->packets_received;
 1271         else
 1272             pkts_out = 0;
 1273 
 1274         pkts_inj = pkt_stats->packets_injected;
 1275 #ifdef ACTIVE_RESPONSE
 1276         pkts_inj += Active_GetInjects();
 1277 #endif
 1278 
 1279         LogMessage("%s\n", STATS_SEPARATOR);
 1280         LogMessage("Packet I/O Totals:\n");
 1281 
 1282         LogCount("Received", pkts_recv);
 1283         LogStat("Analyzed", pkt_stats->packets_received, pkts_recv);
 1284         LogStat("Dropped", pkts_drop, pkts_recv + pkts_drop);
 1285         LogStat("Filtered", pkt_stats->packets_filtered, pkts_recv);
 1286         LogStat("Outstanding", pkts_out, pkts_recv);
 1287         LogCount("Injected", pkts_inj);
 1288 
 1289 #ifdef REG_TEST
 1290         if ( snort_conf->pkt_skip )
 1291             LogCount("Skipped", snort_conf->pkt_skip);
 1292 #endif
 1293     }
 1294 
 1295     LogMessage("%s\n", STATS_SEPARATOR);
 1296     LogMessage("Breakdown by protocol (includes rebuilt packets):\n");
 1297 
 1298     LogStat("Eth", pc.eth, total);
 1299     LogStat("VLAN", pc.vlan, total);
 1300 
 1301     if (pc.nested_vlan != 0)
 1302         LogStat("Nested VLAN", pc.nested_vlan, total);
 1303 
 1304     LogStat("IP4", pc.ip, total);
 1305     LogStat("Frag", pc.frags, total);
 1306     LogStat("ICMP", pc.icmp, total);
 1307     LogStat("UDP", pc.udp, total);
 1308     LogStat("TCP", pc.tcp, total);
 1309 
 1310     LogStat("IP6", pc.ipv6, total);
 1311     LogStat("IP6 Ext", pc.ip6ext, total);
 1312     LogStat("IP6 Opts", pc.ipv6opts, total);
 1313     LogStat("Frag6", pc.frag6, total);
 1314     LogStat("ICMP6", pc.icmp6, total);
 1315     LogStat("UDP6", pc.udp6, total);
 1316     LogStat("TCP6", pc.tcp6, total);
 1317     LogStat("Teredo", pc.teredo, total);
 1318 
 1319     LogStat("ICMP-IP", pc.embdip, total);
 1320 
 1321 #ifndef NO_NON_ETHER_DECODER
 1322     LogStat("EAPOL", pc.eapol, total);
 1323 #endif
 1324 #ifdef GRE
 1325     LogStat("IP4/IP4", pc.ip4ip4, total);
 1326     LogStat("IP4/IP6", pc.ip4ip6, total);
 1327     LogStat("IP6/IP4", pc.ip6ip4, total);
 1328     LogStat("IP6/IP6", pc.ip6ip6, total);
 1329 
 1330     LogStat("GRE", pc.gre, total);
 1331     LogStat("GRE Eth", pc.gre_eth, total);
 1332     LogStat("GRE VLAN", pc.gre_vlan, total);
 1333     LogStat("GRE IP4", pc.gre_ip, total);
 1334     LogStat("GRE IP6", pc.gre_ipv6, total);
 1335     LogStat("GRE IP6 Ext", pc.gre_ipv6ext, total);
 1336     LogStat("GRE PPTP", pc.gre_ppp, total);
 1337     LogStat("GRE ARP", pc.gre_arp, total);
 1338     LogStat("GRE IPX", pc.gre_ipx, total);
 1339     LogStat("GRE Loop", pc.gre_loopback, total);
 1340 #endif  /* GRE */
 1341 #ifdef MPLS
 1342     LogStat("MPLS", pc.mpls, total);
 1343 #endif
 1344     LogStat("ARP", pc.arp, total);
 1345     LogStat("IPX", pc.ipx, total);
 1346     LogStat("Eth Loop", pc.ethloopback, total);
 1347     LogStat("Eth Disc", pc.ethdisc, total);
 1348     LogStat("IP4 Disc", pc.ipdisc, total);
 1349     LogStat("IP6 Disc", pc.ipv6disc, total);
 1350     LogStat("TCP Disc", pc.tdisc, total);
 1351     LogStat("UDP Disc", pc.udisc, total);
 1352     LogStat("ICMP Disc", pc.icmpdisc, total);
 1353     LogStat("All Discard", pc.discards, total);
 1354 
 1355     LogStat("Other", pc.other, total);
 1356     LogStat("Bad Chk Sum", pc.invalid_checksums, total);
 1357     LogStat("Bad TTL", pc.bad_ttl, total);
 1358 
 1359     LogStat("S5 G 1", pc.s5tcp1, total);
 1360     LogStat("S5 G 2", pc.s5tcp2, total);
 1361 
 1362     if ( InternalEventIsEnabled(snort_conf->rate_filter_config,
 1363                 INTERNAL_EVENT_SYN_RECEIVED) )
 1364     {
 1365         LogStat("SYN RL Evnt", pc.syn_rate_limit_events, total);
 1366         LogStat("SYN RL Drop", pc.syn_rate_limit_drops, total);
 1367     }
 1368 
 1369     LogCount("Total", total);
 1370 
 1371     if ( !ScPacketDumpMode() && !ScPacketLogMode() )
 1372     {
 1373         int i;
 1374 
 1375         // ensure proper counting of log_limit
 1376         SnortEventqResetCounts();
 1377 
 1378         LogMessage("%s\n", STATS_SEPARATOR);
 1379         LogMessage("Action Stats:\n");
 1380 
 1381         LogStat("Alerts", pc.total_alert_pkts, total);
 1382         LogStat("Logged", pc.log_pkts, total);
 1383         LogStat("Passed", pc.pass_pkts, total);
 1384 
 1385         LogMessage("Limits:\n");
 1386 
 1387         LogCount("Match", pc.match_limit);
 1388         LogCount("Queue", pc.queue_limit);
 1389         LogCount("Log", pc.log_limit);
 1390         LogCount("Event", pc.event_limit);
 1391         LogCount("Alert", pc.alert_limit);
 1392 
 1393 
 1394         LogMessage("Verdicts:\n");
 1395 
 1396         for ( i = 0; i < MAX_DAQ_VERDICT; i++ )
 1397         {
 1398             const char* s = Verdicts[i];
 1399             LogStat(s, pkt_stats->verdicts[i], pkts_recv);
 1400         }
 1401         if ( pc.internal_blacklist > 0 )
 1402             LogStat("Int Blklst", pc.internal_blacklist, pkts_recv);
 1403 
 1404         if ( pc.internal_whitelist > 0 )
 1405             LogStat("Int Whtlst", pc.internal_whitelist, pkts_recv);
 1406     }
 1407 #ifdef TARGET_BASED
 1408     if (ScIdsMode() && IsAdaptiveConfigured())
 1409     {
 1410         LogMessage("%s\n", STATS_SEPARATOR);
 1411         LogMessage("Attribute Table Stats:\n");
 1412 
 1413         LogCount("Number Entries", (uint64_t)SFAT_NumberOfHosts());
 1414         LogCount("Table Reloaded", pc.attribute_table_reloads);
 1415     }
 1416 #endif  /* TARGET_BASED */
 1417 
 1418     //mpse_print_qinfo();
 1419 
 1420 #ifndef NO_NON_ETHER_DECODER
 1421 #ifdef DLT_IEEE802_11
 1422     if(DAQ_GetBaseProtocol() == DLT_IEEE802_11)
 1423     {
 1424         LogMessage("%s\n", STATS_SEPARATOR);
 1425         LogMessage("Wireless Stats:\n");
 1426         LogMessage("Breakdown by type:\n");
 1427 
 1428         LogStat("Management Packets", pc.wifi_mgmt, total);
 1429         LogStat("Control Packets", pc.wifi_control, total);
 1430         LogStat("Data Packets", pc.wifi_data, total);
 1431     }
 1432 #endif  /* DLT_IEEE802_11 */
 1433 #endif  // NO_NON_ETHER_DECODER
 1434 
 1435     for (idx = preproc_stats_funcs; idx != NULL; idx = idx->next)
 1436     {
 1437         LogMessage("%s\n", STATS_SEPARATOR);
 1438         idx->func(exiting ? 1 : 0);
 1439     }
 1440 
 1441 #ifdef SIDE_CHANNEL
 1442     SideChannelStats(exiting, STATS_SEPARATOR);
 1443 #endif /* SIDE_CHANNEL */
 1444 
 1445     LogMessage("%s\n", STATS_SEPARATOR);
 1446 }
 1447 
 1448 /****************************************************************************
 1449  *
 1450  * Function: CleanupProtoNames()
 1451  *
 1452  * Purpose: Frees the protocol names
 1453  *
 1454  * Arguments: None.
 1455  *
 1456  * Returns: void function
 1457  *
 1458  ****************************************************************************/
 1459 void CleanupProtoNames(void)
 1460 {
 1461     int i;
 1462 
 1463     for(i = 0; i < 256; i++)
 1464     {
 1465         if( protocol_names[i] != NULL )
 1466         {
 1467             free( protocol_names[i] );
 1468             protocol_names[i] = NULL;
 1469         }
 1470     }
 1471 }
 1472 
 1473 /****************************************************************************
 1474  *
 1475  * Function: read_infile(char *)
 1476  *
 1477  * Purpose: Reads the BPF filters in from a file.  Ripped from tcpdump.
 1478  *
 1479  * Arguments: fname => the name of the file containing the BPF filters
 1480  *
 1481  * Returns: the processed BPF string
 1482  *
 1483  ****************************************************************************/
 1484 char *read_infile(char *fname)
 1485 {
 1486     register int fd, cc;
 1487     register char *cp, *cmt;
 1488     struct stat buf;
 1489 
 1490     fd = open(fname, O_RDONLY);
 1491 
 1492     if(fd < 0)
 1493         FatalError("can't open %s: %s\n", fname, strerror(errno));
 1494 
 1495     if(fstat(fd, &buf) < 0)
 1496         FatalError("can't stat %s: %s\n", fname, strerror(errno));
 1497 
 1498     cp = (char *)SnortAlloc(((u_int)buf.st_size + 1) * sizeof(char));
 1499 
 1500     cc = read(fd, cp, (int) buf.st_size);
 1501 
 1502     if(cc < 0)
 1503         FatalError("read %s: %s\n", fname, strerror(errno));
 1504 
 1505     if(cc != buf.st_size)
 1506         FatalError("short read %s (%d != %d)\n", fname, cc, (int) buf.st_size);
 1507 
 1508     cp[(int) buf.st_size] = '\0';
 1509 
 1510     close(fd);
 1511 
 1512     /* Treat everything upto the end of the line as a space
 1513      *  so that we can put comments in our BPF filters
 1514      */
 1515 
 1516     while((cmt = strchr(cp, '#')) != NULL)
 1517     {
 1518         while (*cmt != '\r' && *cmt != '\n' && *cmt != '\0')
 1519         {
 1520             *cmt++ = ' ';
 1521         }
 1522     }
 1523 
 1524     /** LogMessage("BPF filter file: %s\n", fname); **/
 1525 
 1526     return(cp);
 1527 }
 1528 
 1529 
 1530  /****************************************************************************
 1531   *
 1532   * Function: CheckLogDir()
 1533   *
 1534   * Purpose: CyberPsychotic sez: basically we only check if logdir exist and
 1535   *          writable, since it might screw the whole thing in the middle. Any
 1536   *          other checks could be performed here as well.
 1537   *
 1538   * Arguments: None.
 1539   *
 1540   * Returns: void function
 1541   *
 1542   ****************************************************************************/
 1543 void CheckLogDir(void)
 1544 {
 1545     struct stat st;
 1546 
 1547     if (snort_conf->log_dir == NULL)
 1548         return;
 1549 
 1550     if (stat(snort_conf->log_dir, &st) == -1)
 1551         FatalError("Stat check on log dir failed: %s.\n", strerror(errno));
 1552 
 1553     if (!S_ISDIR(st.st_mode) || (access(snort_conf->log_dir, W_OK) == -1))
 1554     {
 1555         FatalError("Can not get write access to logging directory \"%s\". "
 1556                    "(directory doesn't exist or permissions are set incorrectly "
 1557                    "or it is not a directory at all)\n",
 1558                    snort_conf->log_dir);
 1559     }
 1560 }
 1561 
 1562 /* Signal handler for child process signaling the parent
 1563  * that is is ready */
 1564 static volatile int parent_wait = 1;
 1565 static void SigChildReadyHandler(int signal)
 1566 {
 1567     parent_wait = 0;
 1568 }
 1569 
 1570 /****************************************************************************
 1571  *
 1572  * Function: GoDaemon()
 1573  *
 1574  * Purpose: Puts the program into daemon mode, nice and quiet like....
 1575  *
 1576  * Arguments: None.
 1577  *
 1578  * Returns: void function
 1579  *
 1580  ****************************************************************************/
 1581 void GoDaemon(void)
 1582 {
 1583 #ifndef WIN32
 1584 
 1585     int exit_val = 0;
 1586     pid_t cpid;
 1587 
 1588     if (ScDaemonRestart())
 1589         return;
 1590 
 1591     LogMessage("Initializing daemon mode\n");
 1592 
 1593     /* Don't daemonize if we've already daemonized and
 1594      * received a SIGNAL_SNORT_RELOAD. */
 1595     if(getppid() != 1)
 1596     {
 1597         /* Register signal handler that parent can trap signal */
 1598         SnortAddSignal(SIGNAL_SNORT_CHILD_READY, SigChildReadyHandler, 1);
 1599 
 1600         if (errno != 0)
 1601             errno = 0;
 1602 
 1603         /* now fork the child */
 1604         printf("Spawning daemon child...\n");
 1605         cpid = fork();
 1606 
 1607         if(cpid > 0)
 1608         {
 1609             /* Continue waiting until receiving signal from child */
 1610             int status;
 1611             /* Parent */
 1612             printf("My daemon child %d lives...\n", cpid);
 1613 
 1614             /* Don't exit quite yet.  Wait for the child
 1615              * to signal that is there and created the PID
 1616              * file.
 1617              */
 1618             do
 1619             {
 1620 #ifdef DEBUG
 1621                 printf("Parent waiting for child...\n");
 1622 #endif
 1623                 sleep(1);
 1624 
 1625             } while (parent_wait);
 1626 
 1627             if (waitpid(cpid, &status, WNOHANG) == cpid)
 1628             {
 1629                 if (WIFEXITED(status))
 1630                 {
 1631                     LogMessage("Child exited unexpectedly\n");
 1632                     exit_val = -1;
 1633                 }
 1634 
 1635                 else if (WIFSIGNALED(status))
 1636                 {
 1637                     LogMessage("Child terminated unexpectedly\n");
 1638                     exit_val = -2;
 1639                 }
 1640             }
 1641 #ifdef DEBUG
 1642             printf("Child terminated unexpectedly (%d)\n", status);
 1643 #endif
 1644             printf("Daemon parent exiting (%d)\n", exit_val);
 1645 
 1646             exit(exit_val);                /* parent */
 1647         }
 1648 
 1649         if(cpid < 0)
 1650         {
 1651             /* Daemonizing failed... */
 1652             perror("fork");
 1653             exit(1);
 1654         }
 1655     }
 1656     /* Child */
 1657     setsid();
 1658 
 1659     close(0);
 1660     close(1);
 1661     close(2);
 1662 
 1663 #ifdef DEBUG
 1664     /* redirect stdin/stdout/stderr to a file */
 1665     open("/tmp/snort.debug", O_CREAT | O_RDWR);  /* stdin, fd 0 */
 1666 
 1667     /* Change ownership to that which we will drop privileges to */
 1668     if ((snort_conf->user_id != -1) || (snort_conf->group_id != -1))
 1669     {
 1670         uid_t user_id = getuid();
 1671         gid_t group_id = getgid();
 1672 
 1673         if (snort_conf->user_id != -1)
 1674             user_id = snort_conf->user_id;
 1675         if (snort_conf->group_id != -1)
 1676             group_id = snort_conf->group_id;
 1677 
 1678         chown("/tmp/snort.debug", user_id, group_id);
 1679     }
 1680 #else
 1681     /* redirect stdin/stdout/stderr to /dev/null */
 1682     (void)open("/dev/null", O_RDWR);  /* stdin, fd 0 */
 1683 #endif
 1684 
 1685     if (dup(0)) {}  /* stdout, fd 0 => fd 1 */
 1686     if (dup(0)) {}  /* stderr, fd 0 => fd 2 */
 1687 
 1688     SignalWaitingParent();
 1689 #endif /* ! WIN32 */
 1690 }
 1691 
 1692 /* Signal the parent that child is ready */
 1693 void SignalWaitingParent(void)
 1694 {
 1695 #ifndef WIN32
 1696     pid_t ppid = getppid();
 1697 #ifdef DEBUG
 1698     printf("Signaling parent %d from child %d\n", ppid, getpid());
 1699 #endif
 1700 
 1701     if (kill(ppid, SIGNAL_SNORT_CHILD_READY))
 1702     {
 1703         LogMessage("Daemon initialized, failed to signal parent pid: "
 1704             "%d, failure: %d, %s\n", ppid, errno, strerror(errno));
 1705     }
 1706     else
 1707     {
 1708         LogMessage("Daemon initialized, signaled parent pid: %d\n", ppid);
 1709     }
 1710 #endif
 1711 }
 1712 
 1713 /* Guaranteed to be '\0' terminated even if truncation occurs.
 1714  *
 1715  * returns  SNORT_SNPRINTF_SUCCESS if successful
 1716  * returns  SNORT_SNPRINTF_TRUNCATION on truncation
 1717  * returns  SNORT_SNPRINTF_ERROR on error
 1718  */
 1719 int SnortSnprintf(char *buf, size_t buf_size, const char *format, ...)
 1720 {
 1721     va_list ap;
 1722     int ret;
 1723 
 1724     if (buf == NULL || buf_size <= 0 || format == NULL)
 1725         return SNORT_SNPRINTF_ERROR;
 1726 
 1727     /* zero first byte in case an error occurs with
 1728      * vsnprintf, so buffer is null terminated with
 1729      * zero length */
 1730     buf[0] = '\0';
 1731     buf[buf_size - 1] = '\0';
 1732 
 1733     va_start(ap, format);
 1734 
 1735     ret = vsnprintf(buf, buf_size, format, ap);
 1736 
 1737     va_end(ap);
 1738 
 1739     if (ret < 0)
 1740         return SNORT_SNPRINTF_ERROR;
 1741 
 1742     if (buf[buf_size - 1] != '\0' || (size_t)ret >= buf_size)
 1743     {
 1744         /* result was truncated */
 1745         buf[buf_size - 1] = '\0';
 1746         return SNORT_SNPRINTF_TRUNCATION;
 1747     }
 1748 
 1749     return SNORT_SNPRINTF_SUCCESS;
 1750 }
 1751 
 1752 /* Appends to a given string
 1753  * Guaranteed to be '\0' terminated even if truncation occurs.
 1754  *
 1755  * returns SNORT_SNPRINTF_SUCCESS if successful
 1756  * returns SNORT_SNPRINTF_TRUNCATION on truncation
 1757  * returns SNORT_SNPRINTF_ERROR on error
 1758  */
 1759 int SnortSnprintfAppend(char *buf, size_t buf_size, const char *format, ...)
 1760 {
 1761     int str_len;
 1762     int ret;
 1763     va_list ap;
 1764 
 1765     if (buf == NULL || buf_size <= 0 || format == NULL)
 1766         return SNORT_SNPRINTF_ERROR;
 1767 
 1768     str_len = SnortStrnlen(buf, buf_size);
 1769 
 1770     /* since we've already checked buf and buf_size an error
 1771      * indicates no null termination, so just start at
 1772      * beginning of buffer */
 1773     if (str_len == SNORT_STRNLEN_ERROR)
 1774     {
 1775         buf[0] = '\0';
 1776         str_len = 0;
 1777     }
 1778 
 1779     buf[buf_size - 1] = '\0';
 1780 
 1781     va_start(ap, format);
 1782 
 1783     ret = vsnprintf(buf + str_len, buf_size - (size_t)str_len, format, ap);
 1784 
 1785     va_end(ap);
 1786 
 1787     if (ret < 0)
 1788         return SNORT_SNPRINTF_ERROR;
 1789 
 1790     if (buf[buf_size - 1] != '\0' || (size_t)ret >= buf_size)
 1791     {
 1792         /* truncation occured */
 1793         buf[buf_size - 1] = '\0';
 1794         return SNORT_SNPRINTF_TRUNCATION;
 1795     }
 1796 
 1797     return SNORT_SNPRINTF_SUCCESS;
 1798 }
 1799 
 1800 /* Guaranteed to be '\0' terminated even if truncation occurs.
 1801  *
 1802  * Arguments:  dst - the string to contain the copy
 1803  *             src - the string to copy from
 1804  *             dst_size - the size of the destination buffer
 1805  *                        including the null byte.
 1806  *
 1807  * returns SNORT_STRNCPY_SUCCESS if successful
 1808  * returns SNORT_STRNCPY_TRUNCATION on truncation
 1809  * returns SNORT_STRNCPY_ERROR on error
 1810  *
 1811  * Note: Do not set dst[0] = '\0' on error since it's possible that
 1812  * dst and src are the same pointer - it will at least be null
 1813  * terminated in any case
 1814  */
 1815 int SnortStrncpy(char *dst, const char *src, size_t dst_size)
 1816 {
 1817     char *ret = NULL;
 1818 
 1819     if (dst == NULL || src == NULL || dst_size <= 0)
 1820         return SNORT_STRNCPY_ERROR;
 1821 
 1822     dst[dst_size - 1] = '\0';
 1823 
 1824     ret = strncpy(dst, src, dst_size);
 1825 
 1826     /* Not sure if this ever happens but might as
 1827      * well be on the safe side */
 1828     if (ret == NULL)
 1829         return SNORT_STRNCPY_ERROR;
 1830 
 1831     if (dst[dst_size - 1] != '\0')
 1832     {
 1833         /* result was truncated */
 1834         dst[dst_size - 1] = '\0';
 1835         return SNORT_STRNCPY_TRUNCATION;
 1836     }
 1837 
 1838     return SNORT_STRNCPY_SUCCESS;
 1839 }
 1840 
 1841 char *SnortStrndup(const char *src, size_t dst_size)
 1842 {
 1843     char *ret = SnortAlloc(dst_size + 1);
 1844     int ret_val;
 1845 
 1846     ret_val = SnortStrncpy(ret, src, dst_size + 1);
 1847 
 1848     if(ret_val == SNORT_STRNCPY_ERROR)
 1849     {
 1850         free(ret);
 1851         return NULL;
 1852     }
 1853 
 1854     return ret;
 1855 }
 1856 
 1857 /* Determines whether a buffer is '\0' terminated and returns the
 1858  * string length if so
 1859  *
 1860  * returns the string length if '\0' terminated
 1861  * returns SNORT_STRNLEN_ERROR if not '\0' terminated
 1862  */
 1863 int SnortStrnlen(const char *buf, int buf_size)
 1864 {
 1865     int i = 0;
 1866 
 1867     if (buf == NULL || buf_size <= 0)
 1868         return SNORT_STRNLEN_ERROR;
 1869 
 1870     for (i = 0; i < buf_size; i++)
 1871     {
 1872         if (buf[i] == '\0')
 1873             break;
 1874     }
 1875 
 1876     if (i == buf_size)
 1877         return SNORT_STRNLEN_ERROR;
 1878 
 1879     return i;
 1880 }
 1881 
 1882 char * SnortStrdup(const char *str)
 1883 {
 1884     char *copy = NULL;
 1885 
 1886     if (!str)
 1887     {
 1888         FatalError("Unable to duplicate string: NULL!\n");
 1889     }
 1890 
 1891     copy = strdup(str);
 1892 
 1893     if (copy == NULL)
 1894     {
 1895         FatalError("Unable to duplicate string: %s!\n", str);
 1896     }
 1897 
 1898     return copy;
 1899 }
 1900 
 1901 /*
 1902  * Find first occurrence of char of accept in s, limited by slen.
 1903  * A 'safe' version of strpbrk that won't read past end of buffer s
 1904  * in cases that s is not NULL terminated.
 1905  *
 1906  * This code assumes 'accept' is a static string.
 1907  */
 1908 const char *SnortStrnPbrk(const char *s, int slen, const char *accept)
 1909 {
 1910     char ch;
 1911     const char *s_end;
 1912     if (!s || (slen == 0) || !*s || !accept)
 1913         return NULL;
 1914 
 1915     s_end = s + slen;
 1916     while (s < s_end)
 1917     {
 1918         ch = *s;
 1919         if (strchr(accept, ch))
 1920             return s;
 1921         s++;
 1922     }
 1923     return NULL;
 1924 }
 1925 
 1926 /*
 1927  * Find first occurrence of searchstr in s, limited by slen.
 1928  * A 'safe' version of strstr that won't read past end of buffer s
 1929  * in cases that s is not NULL terminated.
 1930  */
 1931 const char *SnortStrnStr(const char *s, int slen, const char *searchstr)
 1932 {
 1933     char ch, nc;
 1934     int len;
 1935     if (!s || (slen == 0) || !*s || !searchstr)
 1936         return NULL;
 1937 
 1938     if ((ch = *searchstr++) != 0)
 1939     {
 1940         len = strlen(searchstr);
 1941         do
 1942         {
 1943             do
 1944             {
 1945                 if ((nc = *s++) == 0)
 1946                 {
 1947                     return NULL;
 1948                 }
 1949                 slen--;
 1950                 if (slen == 0)
 1951                     return NULL;
 1952             } while (nc != ch);
 1953             if (slen - len < 0)
 1954                 return NULL;
 1955         } while (memcmp(s, searchstr, len) != 0);
 1956         s--;
 1957     }
 1958     return s;
 1959 }
 1960 
 1961 /*
 1962  * Find first occurrence of substring in s, ignore case.
 1963 */
 1964 const char *SnortStrcasestr(const char *s, int slen, const char *substr)
 1965 {
 1966     char ch, nc;
 1967     int len;
 1968 
 1969     if (!s || (slen == 0) || !*s || !substr)
 1970         return NULL;
 1971 
 1972     if ((ch = *substr++) != 0)
 1973     {
 1974         ch = tolower((char)ch);
 1975         len = strlen(substr);
 1976         do
 1977         {
 1978             do
 1979             {
 1980                 if ((nc = *s++) == 0)
 1981                 {
 1982                     return NULL;
 1983                 }
 1984                 slen--;
 1985                 if(slen == 0)
 1986                     return NULL;
 1987             } while ((char)tolower((uint8_t)nc) != ch);
 1988             if(slen - len < 0)
 1989                 return NULL;
 1990         } while (strncasecmp(s, substr, len) != 0);
 1991         s--;
 1992     }
 1993     return s;
 1994 }
 1995 
 1996 void * SnortAlloc2(size_t size, const char *format, ...)
 1997 {
 1998     void *tmp;
 1999 
 2000     tmp = (void *)calloc(size, sizeof(char));
 2001 
 2002     if(tmp == NULL)
 2003     {
 2004         va_list ap;
 2005         char buf[STD_BUF];
 2006 
 2007         buf[STD_BUF - 1] = '\0';
 2008 
 2009         va_start(ap, format);
 2010 
 2011         vsnprintf(buf, STD_BUF - 1, format, ap);
 2012 
 2013         va_end(ap);
 2014 
 2015         FatalError("%s", buf);
 2016     }
 2017 
 2018     return tmp;
 2019 }
 2020 
 2021 /**
 2022  * Chroot and adjust the snort_conf->log_dir reference
 2023  *
 2024  * @param directory directory to chroot to
 2025  * @param logstore ptr to snort_conf->log_dir which must be dynamically allocated
 2026  */
 2027 void SetChroot(char *directory, char **logstore)
 2028 {
 2029 #ifdef WIN32
 2030     FatalError("SetChroot() should not be called under Win32!\n");
 2031 #else
 2032     char *absdir;
 2033     size_t abslen;
 2034     char *logdir;
 2035 
 2036     if(!directory || !logstore)
 2037     {
 2038         FatalError("Null parameter passed\n");
 2039     }
 2040 
 2041     logdir = *logstore;
 2042 
 2043     if(logdir == NULL || *logdir == '\0')
 2044     {
 2045         FatalError("Null log directory\n");
 2046     }
 2047 
 2048     DEBUG_WRAP(DebugMessage(DEBUG_INIT,"SetChroot: %s\n",
 2049                                        CurrentWorkingDir()););
 2050 
 2051     logdir = GetAbsolutePath(logdir);
 2052 
 2053     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "SetChroot: %s\n",
 2054                                        CurrentWorkingDir()));
 2055 
 2056     logdir = SnortStrdup(logdir);
 2057 
 2058     /* We're going to reset logstore, so free it now */
 2059     free(*logstore);
 2060     *logstore = NULL;
 2061 
 2062     /* change to the directory */
 2063     if(chdir(directory) != 0)
 2064     {
 2065         FatalError("SetChroot: Can not chdir to \"%s\": %s\n", directory,
 2066                    strerror(errno));
 2067     }
 2068 
 2069     /* always returns an absolute pathname */
 2070     absdir = CurrentWorkingDir();
 2071 
 2072     if(absdir == NULL)
 2073     {
 2074         FatalError("NULL Chroot found\n");
 2075     }
 2076 
 2077     abslen = strlen(absdir);
 2078 
 2079     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "ABS: %s %d\n", absdir, abslen););
 2080 
 2081     /* make the chroot call */
 2082     if(chroot(absdir) < 0)
 2083     {
 2084         FatalError("Can not chroot to \"%s\": absolute: %s: %s\n",
 2085                    directory, absdir, strerror(errno));
 2086     }
 2087 
 2088     DEBUG_WRAP(DebugMessage(DEBUG_INIT,"chroot success (%s ->", absdir););
 2089     DEBUG_WRAP(DebugMessage(DEBUG_INIT,"%s)\n ", CurrentWorkingDir()););
 2090 
 2091     /* change to "/" in the new directory */
 2092     if(chdir("/") < 0)
 2093     {
 2094         FatalError("Can not chdir to \"/\" after chroot: %s\n",
 2095                    strerror(errno));
 2096     }
 2097 
 2098     DEBUG_WRAP(DebugMessage(DEBUG_INIT,"chdir success (%s)\n",
 2099                             CurrentWorkingDir()););
 2100 
 2101 
 2102     if(strncmp(absdir, logdir, strlen(absdir)))
 2103     {
 2104         FatalError("Absdir is not a subset of the logdir");
 2105     }
 2106 
 2107     if(abslen >= strlen(logdir))
 2108     {
 2109         *logstore = SnortStrdup("/");
 2110     }
 2111     else
 2112     {
 2113         *logstore = SnortStrdup(logdir + abslen);
 2114     }
 2115 
 2116     DEBUG_WRAP(DebugMessage(DEBUG_INIT,"new logdir from %s to %s\n",
 2117                             logdir, *logstore));
 2118 
 2119     LogMessage("Chroot directory = %s\n", directory);
 2120 
 2121     if(logdir != NULL)
 2122         free(logdir);
 2123 
 2124 #if 0
 2125     /* XXX XXX */
 2126     /* install the I can't do this signal handler */
 2127     signal(SIGNAL_SNORT_RELOAD, SigCantHupHandler);
 2128 #endif
 2129 #endif /* !WIN32 */
 2130 }
 2131 
 2132 
 2133 /**
 2134  * Return a ptr to the absolute pathname of snort.  This memory must
 2135  * be copied to another region if you wish to save it for later use.
 2136  */
 2137 char *CurrentWorkingDir(void)
 2138 {
 2139     static char buf[PATH_MAX_UTIL + 1];
 2140 
 2141     if(getcwd((char *) buf, PATH_MAX_UTIL) == NULL)
 2142     {
 2143         return NULL;
 2144     }
 2145 
 2146     buf[PATH_MAX_UTIL] = '\0';
 2147 
 2148     return (char *) buf;
 2149 }
 2150 
 2151 /**
 2152  * Given a directory name, return a ptr to a static
 2153  */
 2154 char *GetAbsolutePath(char *dir)
 2155 {
 2156     char *savedir, *dirp;
 2157     static char buf[PATH_MAX_UTIL + 1];
 2158 
 2159     if(dir == NULL)
 2160     {
 2161         return NULL;
 2162     }
 2163 
 2164     savedir = strdup(CurrentWorkingDir());
 2165 
 2166     if(savedir == NULL)
 2167     {
 2168         return NULL;
 2169     }
 2170 
 2171     if(chdir(dir) < 0)
 2172     {
 2173         LogMessage("Can't change to directory: %s\n", dir);
 2174         free(savedir);
 2175         return NULL;
 2176     }
 2177 
 2178     dirp = CurrentWorkingDir();
 2179 
 2180     if(dirp == NULL)
 2181     {
 2182         LogMessage("Unable to access current directory\n");
 2183         free(savedir);
 2184         return NULL;
 2185     }
 2186     else
 2187     {
 2188         strncpy(buf, dirp, PATH_MAX_UTIL);
 2189         buf[PATH_MAX_UTIL] = '\0';
 2190     }
 2191 
 2192     if(chdir(savedir) < 0)
 2193     {
 2194         LogMessage("Can't change back to directory: %s\n", dir);
 2195         free(savedir);
 2196         return NULL;
 2197     }
 2198 
 2199     free(savedir);
 2200     return (char *) buf;
 2201 }
 2202 
 2203 
 2204 #ifndef WIN32
 2205 /* very slow sort - do not use at runtime! */
 2206 SF_LIST * SortDirectory(const char *path)
 2207 {
 2208     SF_LIST *dir_entries;
 2209     DIR *dir;
 2210     struct dirent *direntry;
 2211     int ret = 0;
 2212 
 2213     if (path == NULL)
 2214         return NULL;
 2215 
 2216     dir_entries = sflist_new();
 2217     if (dir_entries == NULL)
 2218     {
 2219         ErrorMessage("Could not allocate new list for directory entries\n");
 2220         return NULL;
 2221     }
 2222 
 2223     dir = opendir(path);
 2224     if (dir == NULL)
 2225     {
 2226         ErrorMessage("Error opening directory: %s: %s\n",
 2227                      path, strerror(errno));
 2228         sflist_free_all(dir_entries, free);
 2229         return NULL;
 2230     }
 2231 
 2232     /* Reset errno since we'll be checking it unconditionally */
 2233     errno = 0;
 2234 
 2235     while ((direntry = readdir(dir)) != NULL)
 2236     {
 2237         char *node_entry_name, *dir_entry_name;
 2238         SF_LNODE *node;
 2239 
 2240         dir_entry_name = SnortStrdup(direntry->d_name);
 2241 
 2242         for (node = sflist_first_node(dir_entries);
 2243              node != NULL;
 2244              node = sflist_next_node(dir_entries))
 2245         {
 2246             node_entry_name = (char *)node->ndata;
 2247             if (strcmp(dir_entry_name, node_entry_name) < 0)
 2248                 break;
 2249         }
 2250 
 2251         if (node == NULL)
 2252             ret = sflist_add_tail(dir_entries, (NODE_DATA)dir_entry_name);
 2253         else
 2254             ret = sflist_add_before(dir_entries, node, (NODE_DATA)dir_entry_name);
 2255 
 2256         if (ret == -1)
 2257         {
 2258             ErrorMessage("Error adding directory entry to list\n");
 2259             sflist_free_all(dir_entries, free);
 2260             closedir(dir);
 2261             return NULL;
 2262         }
 2263     }
 2264 
 2265     if (errno != 0)
 2266     {
 2267         ErrorMessage("Error reading directory: %s: %s\n",
 2268                      path, strerror(errno));
 2269         errno = 0;
 2270         sflist_free_all(dir_entries, free);
 2271         closedir(dir);
 2272         return NULL;
 2273     }
 2274 
 2275     closedir(dir);
 2276 
 2277     return dir_entries;
 2278 }
 2279 
 2280 int GetFilesUnderDir(const char *path, SF_QUEUE *dir_queue, const char *filter)
 2281 {
 2282     SF_LIST *dir_entries;
 2283     char *direntry;
 2284     int ret = 0;
 2285     int num_files = 0;
 2286 
 2287     if ((path == NULL) || (dir_queue == NULL))
 2288         return -1;
 2289 
 2290     dir_entries = SortDirectory(path);
 2291     if (dir_entries == NULL)
 2292     {
 2293         ErrorMessage("Error sorting entries in directory: %s\n", path);
 2294         return -1;
 2295     }
 2296 
 2297     for (direntry = (char *)sflist_first(dir_entries);
 2298          direntry != NULL;
 2299          direntry = (char *)sflist_next(dir_entries))
 2300     {
 2301         char path_buf[PATH_MAX];
 2302         struct stat file_stat;
 2303 
 2304         /* Don't look at dot files */
 2305         if (strncmp(".", direntry, 1) == 0)
 2306             continue;
 2307 
 2308         ret = SnortSnprintf(path_buf, PATH_MAX, "%s%s%s",
 2309                             path, path[strlen(path) - 1] == '/' ? "" : "/", direntry);
 2310         if (ret == SNORT_SNPRINTF_TRUNCATION)
 2311         {
 2312             ErrorMessage("Error copying file to buffer: Path too long\n");
 2313             sflist_free_all(dir_entries, free);
 2314             return -1;
 2315         }
 2316         else if (ret != SNORT_SNPRINTF_SUCCESS)
 2317         {
 2318             ErrorMessage("Error copying file to buffer\n");
 2319             sflist_free_all(dir_entries, free);
 2320             return -1;
 2321         }
 2322 
 2323         ret = stat(path_buf, &file_stat);
 2324         if (ret == -1)
 2325         {
 2326             ErrorMessage("Could not stat file: %s: %s\n",
 2327                          path_buf, strerror(errno));
 2328             continue;
 2329         }
 2330 
 2331         if (file_stat.st_mode & S_IFDIR)
 2332         {
 2333             ret = GetFilesUnderDir(path_buf, dir_queue, filter);
 2334             if (ret == -1)
 2335             {
 2336                 sflist_free_all(dir_entries, free);
 2337                 return -1;
 2338             }
 2339 
 2340             num_files += ret;
 2341         }
 2342         else if (file_stat.st_mode & S_IFREG)
 2343         {
 2344             if ((filter == NULL) || (fnmatch(filter, direntry, 0) == 0))
 2345             {
 2346                 char *file = SnortStrdup(path_buf);
 2347 
 2348                 ret = sfqueue_add(dir_queue, (NODE_DATA)file);
 2349                 if (ret == -1)
 2350                 {
 2351                     ErrorMessage("Could not append item to list: %s\n", file);
 2352                     free(file);
 2353                     sflist_free_all(dir_entries, free);
 2354                     return -1;
 2355                 }
 2356 
 2357                 num_files++;
 2358             }
 2359         }
 2360     }
 2361 
 2362     sflist_free_all(dir_entries, free);
 2363 
 2364     return num_files;
 2365 }
 2366 #endif
 2367 
 2368 /****************************************************************************
 2369  *
 2370  * Function: hex(u_char *xdata, int length)
 2371  *
 2372  * Purpose: This function takes takes a buffer "xdata" and its length then
 2373  *          returns a string of hex with no spaces
 2374  *
 2375  * Arguments: xdata is the buffer, length is the length of the buffer in
 2376  *            bytes
 2377  *
 2378  * Returns: char * -- You must free this char * when you are done with it.
 2379  *
 2380  ***************************************************************************/
 2381 char *hex(const u_char *xdata, int length)
 2382 {
 2383     int x;
 2384     char *rval = NULL;
 2385     char *buf = NULL;
 2386 
 2387     if (xdata == NULL)
 2388         return NULL;
 2389 
 2390     buf = (char *)calloc((length * 2) + 1, sizeof(char));
 2391 
 2392     if (buf != NULL)
 2393     {
 2394         rval = buf;
 2395 
 2396         for (x = 0; x < length; x++)
 2397         {
 2398             SnortSnprintf(buf, 3, "%02X", xdata[x]);
 2399             buf += 2;
 2400         }
 2401 
 2402         rval[length * 2] = '\0';
 2403     }
 2404 
 2405     return rval;
 2406 }
 2407 
 2408 /****************************************************************************
 2409  *
 2410  * Function: fasthex(u_char *xdata, int length)
 2411  *
 2412  * Purpose: Outputs a purdy fugly hex output, only used by mstring with
 2413  * DEBUG_MSGS enabled.
 2414  *
 2415  * Arguments: xdata is the buffer, length is the length of the buffer in
 2416  *            bytes
 2417  *
 2418  * Returns: char * -- You must free this char * when you are done with it.
 2419  *
 2420  ***************************************************************************/
 2421 char *fasthex(const u_char *xdata, int length)
 2422 {
 2423     char conv[] = "0123456789ABCDEF";
 2424     char *retbuf = NULL;
 2425     const u_char *index;
 2426     const u_char *end;
 2427     char *ridx;
 2428 
 2429     index = xdata;
 2430     end = xdata + length;
 2431     retbuf = (char *)SnortAlloc(((length * 2) + 1) * sizeof(char));
 2432     ridx = retbuf;
 2433 
 2434     while(index < end)
 2435     {
 2436         *ridx++ = conv[((*index & 0xFF)>>4)];
 2437         *ridx++ = conv[((*index & 0xFF)&0x0F)];
 2438         index++;
 2439     }
 2440 
 2441     return retbuf;
 2442 }
 2443 
 2444 /*
 2445  *   Fatal Integer Parser
 2446  *   Ascii to Integer conversion with fatal error support
 2447  */
 2448 int xatol(const char *s , const char *etext)
 2449 {
 2450     long int val;
 2451     char *endptr;
 2452     char *default_error = "xatol() error\n";
 2453 
 2454     if (etext == NULL)
 2455         etext = default_error;
 2456 
 2457     if (s == NULL)
 2458         FatalError("%s: String is NULL\n", etext);
 2459 
 2460     while (isspace((int)*s))
 2461         s++;
 2462 
 2463     if (strlen(s) == 0)
 2464         FatalError("%s: String is empty\n", etext);
 2465 
 2466 
 2467     /*
 2468      *  strtoul - errors on win32 : ERANGE (VS 6.0)
 2469      *            errors on linux : ERANGE, EINVAL
 2470      *               (for EINVAL, unsupported base which won't happen here)
 2471      */
 2472     val = SnortStrtol(s, &endptr, 0);
 2473 
 2474     if ((errno == ERANGE) || (val > INT_MAX) || (val < INT_MIN) || (*endptr != '\0'))
 2475         FatalError("%s: Invalid integer input: %s\n", etext, s);
 2476 
 2477     return (int)val;
 2478 }
 2479 
 2480 /*
 2481  *   Fatal Integer Parser
 2482  *   Ascii to Integer conversion with fatal error support
 2483  */
 2484 unsigned int xatou(const char *s , const char *etext)
 2485 {
 2486     unsigned long int val;
 2487     char *endptr;
 2488     char *default_error = "xatou() error\n";
 2489 
 2490     if (etext == NULL)
 2491         etext = default_error;
 2492 
 2493     if (s == NULL)
 2494         FatalError("%s: String is NULL\n", etext);
 2495 
 2496     while (isspace((int)*s))
 2497         s++;
 2498 
 2499     if (strlen(s) == 0)
 2500         FatalError("%s: String is empty\n", etext);
 2501 
 2502     if (*s == '-')
 2503     {
 2504         FatalError("%s: Invalid unsigned integer - negative sign found, "
 2505                    "input: %s\n", etext, s);
 2506     }
 2507 
 2508 
 2509     /*
 2510      *  strtoul - errors on win32 : ERANGE (VS 6.0)
 2511      *            errors on linux : ERANGE, EINVAL
 2512      */
 2513     val = SnortStrtoul(s, &endptr, 0);
 2514 
 2515     if ((errno == ERANGE) || (val > UINT_MAX) || (*endptr != '\0'))
 2516         FatalError("%s: Invalid integer input: %s\n", etext, s);
 2517 
 2518     return (unsigned int)val;
 2519 }
 2520 
 2521 unsigned int xatoup(const char *s , const char *etext)
 2522 {
 2523     unsigned long int val = xatou(s, etext);
 2524     if ( !val )
 2525         FatalError("%s: must be > 0\n", etext);
 2526     return (unsigned int)val;
 2527 }
 2528 
 2529 char * ObfuscateIpToText(sfaddr_t *ip)
 2530 {
 2531     static char ip_buf1[INET6_ADDRSTRLEN];
 2532     static char ip_buf2[INET6_ADDRSTRLEN];
 2533     static int buf_num = 0;
 2534     int buf_size = INET6_ADDRSTRLEN;
 2535     char *ip_buf;
 2536 
 2537     if (buf_num)
 2538         ip_buf = ip_buf2;
 2539     else
 2540         ip_buf = ip_buf1;
 2541 
 2542     buf_num ^= 1;
 2543     ip_buf[0] = 0;
 2544 
 2545     if (ip == NULL)
 2546         return ip_buf;
 2547 
 2548     if (!sfip_is_set(&snort_conf->obfuscation_net))
 2549     {
 2550         if (sfaddr_family(ip) == AF_INET6)
 2551             SnortSnprintf(ip_buf, buf_size, "x:x:x:x::x:x:x:x");
 2552         else
 2553             SnortSnprintf(ip_buf, buf_size, "xxx.xxx.xxx.xxx");
 2554     }
 2555     else
 2556     {
 2557         sfaddr_t tmp;
 2558         char *tmp_buf;
 2559 
 2560         IP_COPY_VALUE(tmp, ip);
 2561 
 2562         if (sfip_is_set(&snort_conf->homenet))
 2563         {
 2564             if (sfip_contains(&snort_conf->homenet, &tmp) == SFIP_CONTAINS)
 2565                 sfip_obfuscate(&snort_conf->obfuscation_net, &tmp);
 2566         }
 2567         else
 2568         {
 2569             sfip_obfuscate(&snort_conf->obfuscation_net, &tmp);
 2570         }
 2571 
 2572         tmp_buf = sfip_to_str(&tmp);
 2573         SnortSnprintf(ip_buf, buf_size, "%s", tmp_buf);
 2574     }
 2575 
 2576     return ip_buf;
 2577 }
 2578 
 2579 void PrintPacketData(const uint8_t *data, const uint32_t len)
 2580 {
 2581     uint32_t i, j;
 2582     uint32_t total_len = 0;
 2583     uint8_t hex_buf[16];
 2584     uint8_t char_buf[16];
 2585     char *length_chars = "       0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 15\n"
 2586                          "------------------------------------------------------\n";
 2587 
 2588     LogMessage("%s", length_chars);
 2589 
 2590     for (i = 0; i <= len; i++)
 2591     {
 2592         if ((i%16 == 0) && (i != 0))
 2593         {
 2594             LogMessage("%04x  ", total_len);
 2595             total_len += 16;
 2596 
 2597             for (j = 0; j < 16; j++)
 2598             {
 2599                 LogMessage("%02x ", hex_buf[j]);
 2600                 if (j == 7)
 2601                     LogMessage(" ");
 2602             }
 2603 
 2604             LogMessage(" ");
 2605 
 2606             for (j = 0; j < 16; j++)
 2607             {
 2608                 LogMessage("%c", char_buf[j]);
 2609                 if (j == 7)
 2610                     LogMessage(" ");
 2611             }
 2612 
 2613             LogMessage("\n");
 2614         }
 2615 
 2616         if (i == len)
 2617             break;
 2618 
 2619         hex_buf[i%16] = data[i];
 2620 
 2621         if (isprint((int)data[i]))
 2622             char_buf[i%16] = data[i];
 2623         else
 2624             char_buf[i%16] = '.';
 2625     }
 2626 
 2627     if ((i-total_len) > 0)
 2628     {
 2629         LogMessage("%04x  ", total_len);
 2630 
 2631         for (j = 0; j < i-total_len; j++)
 2632         {
 2633             LogMessage("%02x ", hex_buf[j]);
 2634             if (j == 7)
 2635                 LogMessage(" ");
 2636         }
 2637 
 2638         if (j < 8)
 2639             LogMessage(" ");
 2640         LogMessage("%*s", (16-j)*3, "");
 2641         LogMessage(" ");
 2642 
 2643         for (j = 0; j < i-total_len; j++)
 2644         {
 2645             LogMessage("%c", char_buf[j]);
 2646             if (j == 7)
 2647                 LogMessage(" ");
 2648         }
 2649     }
 2650 
 2651     LogMessage("\n");
 2652 }
 2653 
 2654 int CheckValueInRange(const char *value_str, char *option,
 2655         unsigned long lo, unsigned long hi, unsigned long *value)
 2656 {
 2657     char *endptr;
 2658     uint32_t val;
 2659 
 2660     if ( value_str == NULL )
 2661     {
 2662         ParseError("Invalid format for %s.", option);
 2663         return -1;
 2664     }
 2665 
 2666     if (SnortStrToU32(value_str, &endptr, &val, 10))
 2667     {
 2668         ParseError("Invalid format for %s.", option);
 2669         return -1;
 2670     }
 2671 
 2672     if(*endptr)
 2673     {
 2674         ParseError("Invalid format for %s.", option);
 2675         return -1;
 2676     }
 2677 
 2678     *value = val;
 2679 
 2680     if ( (errno == ERANGE) || (*value) < lo || (*value) > hi)
 2681     {
 2682         ParseError("Invalid value for %s. "
 2683                 "It should range between %u and %u.", option,
 2684                 lo, hi);
 2685         return -1;
 2686     }
 2687 
 2688     return 0;
 2689 }
 2690