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