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