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